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

 

Coverage histogram

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

Code metrics

52
141
19
2
431
283
73
0.52
7.42
9.5
3.84

Classes

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