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 MgnlGroovyJCRNode.java

 

Coverage histogram

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

Code metrics

52
141
19
2
428
283
73
0.52
7.42
9.5
3.84

Classes

Class Line # Actions
MgnlGroovyJCRNode 116 138 0% 70 143
0.3058252330.6%
MgnlGroovyJCRNode.MgnlGroovyWrappingNodeIterator 365 3 0% 3 2
0.666666766.7%
 

Contributing tests

This file is covered by 8 tests. .

Source view

1    /**
2    * This file Copyright (c) 2013-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.security.AccessDeniedException;
41    import info.magnolia.jcr.RuntimeRepositoryException;
42    import info.magnolia.jcr.iterator.DelegatingNodeIterator;
43    import info.magnolia.jcr.util.MetaDataUtil;
44    import info.magnolia.jcr.util.NodeTypes;
45    import info.magnolia.jcr.util.NodeUtil;
46    import info.magnolia.jcr.util.PropertyUtil;
47    import info.magnolia.jcr.wrapper.DelegateNodeWrapper;
48   
49    import java.math.BigDecimal;
50    import java.util.ArrayList;
51    import java.util.List;
52   
53    import javax.jcr.Node;
54    import javax.jcr.NodeIterator;
55    import javax.jcr.PathNotFoundException;
56    import javax.jcr.Property;
57    import javax.jcr.PropertyIterator;
58    import javax.jcr.PropertyType;
59    import javax.jcr.RepositoryException;
60    import javax.jcr.Value;
61    import javax.jcr.ValueFormatException;
62   
63    import org.apache.commons.lang.StringUtils;
64    import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
65    import org.slf4j.Logger;
66    import org.slf4j.LoggerFactory;
67   
68    /**
69    * Implementation of wrapped Node object used in Groovy console context.
70    * This makes it possible, for example, navigating the nodes in a Magnolia repository
71    * 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}.
72    * For example, here is how, in a groovy script, one could navigate to and print the node data named <em>abstract</em>:
73    *
74    * <pre>
75    * session = ctx.getJCRSession('website')
76    * node = session.getNode('/demo-project')
77    * println node.about.history.abstract
78    * </pre>
79    *
80    * The above example can also be made more groovy-like by using the <code>@</code> notation to access the property
81    *
82    * <pre>
83    * node.about.history.@abstract
84    * </pre>
85    *
86    * As <code>node</code> is also a {@link Node}, you can call any of its
87    * methods. E.g.
88    *
89    * <pre>
90    * println node.metaData.template
91    * println node.about.title
92    * println node.about.parent <strong>(this can return null)</strong>
93    * </pre>
94    *
95    * <br/>
96    * If you want to iterate over <i>properties</i> for a certain node you can do for instance
97    *
98    * <pre>
99    * node.about.properties.each {println it.name}
100    * </pre>
101    *
102    * It is also possible to assign values to properties or create new ones. E.g.
103    *
104    * <pre>
105    * node.foo = 3.14d
106    * node.bar = true
107    * node.baz = 'some text'
108    * node.qux = 100
109    * </pre>
110    *
111    * 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.
112    * Furthermore, the correct type will be detected based on the value assigned (i.e. Boolean, String, Calendar, Long or Double). <br/>
113    * <br/>
114    * <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.
115    */
 
116    public class MgnlGroovyJCRNode extends DelegateNodeWrapper {
117   
 
118  1 toggle static {
119    // wrap the standard MetaClass with the delegate
120  1 setMetaClass(GroovySystem.getMetaClassRegistry().getMetaClass(MgnlGroovyJCRNode.class), MgnlGroovyJCRNode.class);
121    }
122   
123    protected static final Logger log = LoggerFactory.getLogger(MgnlGroovyJCRNode.class);
124   
125    private String name;
126   
 
127  16 toggle public MgnlGroovyJCRNode(Node node) {
128  16 super(node);
129  16 try {
130  16 this.name = "/".equals(node.getPath()) ? "/root" : getName();
131    } catch (RepositoryException e) {
132  0 throw new RuntimeRepositoryException(e);
133    }
134    }
135   
 
136  1 toggle protected static void setMetaClass(final MetaClass metaClass, Class nodeClass) {
137  1 final MetaClass newMetaClass = new DelegatingMetaClass(metaClass) {
138   
 
139  0 toggle @Override
140    public Object getAttribute(final Object object, final String attribute) {
141  0 MgnlGroovyJCRNode n = (MgnlGroovyJCRNode) object;
142  0 try {
143  0 return n.get("@" + attribute);
144    } catch (ValueFormatException e) {
145  0 log.error(e.getMessage());
146    } catch (RepositoryException e) {
147  0 log.error(e.getMessage());
148    }
149  0 return null;
150    }
151   
 
152  0 toggle @Override
153    public void setAttribute(final Object object, final String attribute, final Object newValue) {
154  0 MgnlGroovyJCRNode n = (MgnlGroovyJCRNode) object;
155  0 try {
156  0 PropertyUtil.setProperty(n, attribute, newValue);
157    }
158    catch (AccessDeniedException e) {
159  0 log.error(e.getMessage());
160    }
161    catch (PathNotFoundException e) {
162  0 log.error(e.getMessage());
163    }
164    catch (RepositoryException e) {
165  0 log.error(e.getMessage());
166    }
167    }
168   
 
169  0 toggle @Override
170    public Object getProperty(Object object, String property) {
171  0 if (object instanceof MgnlGroovyJCRNode) {
172  0 MgnlGroovyJCRNode n = (MgnlGroovyJCRNode) object;
173  0 try {
174  0 return n.get(property);
175    } catch (ValueFormatException e) {
176  0 log.error(e.getMessage());
177    } catch (RepositoryException e) {
178  0 log.error(e.getMessage());
179    }
180  0 return null;
181    }
182  0 return super.getProperty(object, property);
183    }
184   
 
185  0 toggle @Override
186    public void setProperty(Object object, String property, Object newValue) {
187  0 String attribute = null;
188  0 if (property.startsWith("@")) {
189  0 attribute = property.substring(1);
190    } else {
191  0 attribute = property;
192    }
193  0 MgnlGroovyJCRNode n = (MgnlGroovyJCRNode) object;
194  0 try {
195    // else you get java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
196  0 if (newValue instanceof Integer) {
197  0 newValue = ((Integer) newValue).longValue();
198    }
199  0 PropertyUtil.setProperty(n, attribute, newValue);
200    }
201    catch (AccessDeniedException e) {
202  0 log.error(e.getMessage());
203    }
204    catch (PathNotFoundException e) {
205  0 log.error(e.getMessage());
206    }
207    catch (RepositoryException e) {
208  0 log.error(e.getMessage());
209    }
210    }
211    };
212   
213  1 GroovySystem.getMetaClassRegistry().setMetaClass(nodeClass, newMetaClass);
214    }
215   
 
216  0 toggle public String name() {
217  0 return name;
218    }
219   
220    /**
221    * Provides lookup of elements by non-namespaced name.
222    *
223    * @param key the name (or shortcut key) of the node(s) of interest
224    * @return the nodes which match key
225    * @throws RepositoryException
226    * @throws ValueFormatException
227    */
 
228  9 toggle public Object get(String key) throws ValueFormatException, RepositoryException {
229  9 if (key != null && key.charAt(0) == '@') {
230  3 String attributeName = key.substring(1);
231  3 Property property = PropertyUtil.getPropertyOrNull(getWrappedNode(), attributeName);
232  3 return getPropertyValue(property);
233    }
234  6 try {
235  6 if ("parent".equals(key)) {
236  0 return getParent();
237    }
238  6 if ("children".equals(key) || "nodes".equals(key)) {
239  3 Iterable<Node> iterable = NodeUtil.getNodes(getWrappedNode());
240  3 return new MgnlGroovyWrappingNodeIterator(new NodeIteratorAdapter(iterable.iterator()));
241    }
242  3 if ("metaData".equals(key)) {
243  0 return MetaDataUtil.getMetaData(getWrappedNode());
244    }
245  3 if ("properties".equals(key)) {
246  0 return getProperties();
247    }
248  3 if ("name".equals(key)) {
249  1 return name;
250    }
251  2 return new MgnlGroovyJCRNode(getNode(key));
252   
253    } catch (RepositoryException e) {
254  2 log.info(e.getMessage());
255    }
256   
257    // last attempt: lets assume the client requested for an attribute without the @ notation
258  2 Property property = PropertyUtil.getPropertyOrNull(getWrappedNode(), key);
259  2 return getPropertyValue(property);
260    }
261   
262    /**
263    * Returns the value for the given property.
264    * The Java types returned vary according to the underlying {@link PropertyType}.
265    * <ul>
266    * <li> {@link PropertyType#STRING} returns a {@link String}
267    * <li> {@link PropertyType#DATE} returns a {@link java.util.Calendar}
268    * <li> {@link PropertyType#DOUBLE} returns a {@link BigDecimal}
269    * <li> {@link PropertyType#LONG} returns a {@link BigDecimal}
270    * <li> {@link PropertyType#BINARY} returns the {@link java.io.InputStream} value.
271    * <li>All other property types will be returned as {@link String}(s)
272    * </ul>
273    */
 
274  5 toggle protected Object getPropertyValue(Property property) throws RepositoryException, ValueFormatException {
275  5 if (property == null) {
276  0 return "unknown property";
277    }
278  5 if (property.isMultiple()) {
279  0 List<Object> values = new ArrayList<Object>();
280  0 for (Value value : property.getValues()) {
281  0 values.add(getPropertyValueInternal(value));
282    }
283  0 return values;
284    } else {
285  5 return getPropertyValueInternal(property.getValue());
286    }
287   
288    }
289   
 
290  0 toggle public String print() {
291  0 StringBuilder retVal = new StringBuilder();
292  0 try {
293  0 Iterable<Node> nodes = NodeUtil.getNodes(getWrappedNode());
294  0 retVal.append("(+) " + name + "\n");
295  0 for (Node node : nodes) {
296  0 if (!showNode(node)) {
297  0 continue;
298    }
299  0 if ((NodeUtil.getNodes(node).iterator().hasNext())) {
300  0 retVal.append("\t(+) ");
301    } else {
302  0 retVal.append("\t(-) ");
303    }
304  0 retVal.append(node.getName() + "\n");
305    }
306   
307  0 if (getProperties().getSize() > 0) {
308  0 PropertyIterator it = super.getProperties();
309  0 while (it.hasNext()) {
310  0 Property property = it.nextProperty();
311  0 if (!showProperty(property)) {
312  0 continue;
313    }
314  0 String name = property.getName();
315   
316  0 retVal.append("\t\t* " + name + ": ["
317    + StringUtils.abbreviate(getPropertyValue(property).toString(), 80)
318    + "]\n");
319   
320    }
321   
322    }
323    } catch (ValueFormatException e) {
324  0 e.printStackTrace();
325    } catch (RepositoryException e) {
326  0 e.printStackTrace();
327    }
328   
329  0 return retVal.toString();
330    }
331   
 
332  0 toggle @Override
333    public int hashCode() {
334  0 final int prime = 31;
335  0 int result = 1;
336  0 result = prime * result + ((name == null) ? 0 : name.hashCode());
337  0 return result;
338    }
339   
 
340  0 toggle @Override
341    public boolean equals(Object obj) {
342  0 if (this == obj)
343  0 return true;
344  0 if (obj == null)
345  0 return false;
346  0 if (getClass() != obj.getClass())
347  0 return false;
348  0 MgnlGroovyJCRNode other = (MgnlGroovyJCRNode) obj;
349  0 if (name == null) {
350  0 if (other.name != null)
351  0 return false;
352    } else
353  0 try {
354  0 if (!getIdentifier().equals(other.getIdentifier()))
355  0 return false;
356    } catch (RepositoryException e) {
357  0 return false;
358    }
359  0 return true;
360    }
361   
362    /**
363    * MgnlGroovyWrappingNodeIterator.
364    */
 
365    protected class MgnlGroovyWrappingNodeIterator extends DelegatingNodeIterator {
 
366  3 toggle public MgnlGroovyWrappingNodeIterator(NodeIterator iterator) {
367  3 super(iterator);
368    }
369   
 
370  0 toggle @Override
371    public Node nextNode() {
372  0 return new MgnlGroovyJCRNode(super.nextNode());
373    }
374   
 
375  8 toggle @Override
376    public Object next() {
377  8 return new MgnlGroovyJCRNode((Node) super.next());
378    }
379    }
380   
 
381  4 toggle protected boolean showNode(Node node) {
382  4 try {
383  4 if (NodeTypes.MetaData.NAME.equals(node.getPrimaryNodeType().getName())
384    || node.getName().startsWith("jcr:")
385    || node.getName().startsWith("rep:")) {
386  3 return false;
387    }
388    } catch (RepositoryException e) {
389  0 log.error(e.getMessage());
390  0 return false;
391    }
392  1 return true;
393    }
394   
 
395  2 toggle protected boolean showProperty(Property property) {
396  2 try {
397  2 if (property.getName().startsWith("jcr:")) {
398  1 return false;
399    }
400    } catch (RepositoryException e) {
401  0 log.error(e.getMessage());
402  0 return false;
403    }
404  1 return true;
405    }
406   
 
407  5 toggle private Object getPropertyValueInternal(Value property) throws RepositoryException {
408  5 switch (property.getType()) {
409  3 case PropertyType.STRING:
410  3 return property.getString();
411  0 case PropertyType.BOOLEAN:
412  0 return property.getBoolean();
413  0 case PropertyType.BINARY:
414  0 return property.getBinary().getStream();
415  0 case PropertyType.DATE:
416  0 return property.getDate();
417  0 case PropertyType.DECIMAL:
418  0 return property.getDecimal();
419  0 case PropertyType.DOUBLE:
420  0 return BigDecimal.valueOf(property.getDouble());
421  2 case PropertyType.LONG:
422  2 return BigDecimal.valueOf(property.getLong());
423  0 default:
424  0 return property.getString();
425    }
426    }
427   
428    }