Clover icon

Magnolia REST Content Delivery 2.0-rc1

  1. Project Clover database Mon Oct 30 2017 16:36:57 CET
  2. Package info.magnolia.rest.delivery.jcr

File NodeWriter.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart9.png
39% of files have more coverage

Code metrics

14
57
11
1
207
134
25
0.44
5.18
11
2.27

Classes

Class Line # Actions
NodeWriter 71 57 0% 25 15
0.8170731781.7%
 

Contributing tests

This file is covered by 11 tests. .

Source view

1    /**
2    * This file Copyright (c) 2017 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.rest.delivery.jcr;
35   
36    import info.magnolia.cms.util.DateUtil;
37    import info.magnolia.jcr.util.PropertyUtil;
38   
39    import java.io.IOException;
40    import java.io.OutputStream;
41    import java.lang.annotation.Annotation;
42    import java.lang.reflect.Type;
43   
44    import javax.jcr.Node;
45    import javax.jcr.NodeIterator;
46    import javax.jcr.Property;
47    import javax.jcr.PropertyIterator;
48    import javax.jcr.PropertyType;
49    import javax.jcr.RepositoryException;
50    import javax.jcr.Value;
51    import javax.json.Json;
52    import javax.json.JsonArrayBuilder;
53    import javax.json.stream.JsonGenerator;
54    import javax.ws.rs.Produces;
55    import javax.ws.rs.WebApplicationException;
56    import javax.ws.rs.core.MediaType;
57    import javax.ws.rs.core.MultivaluedMap;
58    import javax.ws.rs.ext.MessageBodyWriter;
59    import javax.ws.rs.ext.Provider;
60   
61    import org.apache.commons.codec.binary.Base64;
62    import org.apache.commons.io.IOUtils;
63    import org.slf4j.Logger;
64    import org.slf4j.LoggerFactory;
65   
66    /**
67    * Item content provider.
68    */
69    @Provider
70    @Produces({ MediaType.APPLICATION_JSON })
 
71    public class NodeWriter implements MessageBodyWriter<Node> {
72   
73    private static final Logger log = LoggerFactory.getLogger(NodeWriter.class);
74   
75    private static final String SAME_NAME_SIBLING_PREFIX = "_";
76    private static final String META_PROPERTY_PREFIX = "@";
77    private static final String PATH_PROPERTY = META_PROPERTY_PREFIX + "path";
78    private static final String NAME_PROPERTY = META_PROPERTY_PREFIX + "name";
79    private static final String CHILD_PROPERTY = META_PROPERTY_PREFIX + "nodes";
80   
81    private int currentLevel = 0;
82   
 
83  1 toggle @Override
84    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
85  1 return Node.class.isAssignableFrom(type);
86    }
87   
 
88  0 toggle @Override
89    public long getSize(Node node, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
90    // As of JAX-RS 2.0, the method has been deprecated and the value returned by the method is ignored by a JAX-RS runtime.
91  0 return -1;
92    }
93   
 
94  18 toggle @Override
95    public void writeTo(Node node, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
96  18 JsonGenerator jsonGenerator = entityStream instanceof OutputStreamWrapper ?
97    ((OutputStreamWrapper) entityStream).getJsonGenerator() :
98    Json.createGenerator(entityStream);
99   
100  18 resetCurrentLevel();
101  18 writeNode(jsonGenerator, node);
102   
103  18 if (!OutputStreamWrapper.isWrapped(entityStream)) {
104  6 jsonGenerator.close();
105    }
106    }
107   
 
108  88 toggle private void writeNode(JsonGenerator jsonGenerator, Node node) {
109  88 try {
110  88 enterNode(jsonGenerator, node, currentLevel);
111   
112  88 ++currentLevel;
113   
114  88 writeSpecialProperties(jsonGenerator, node);
115   
116  88 PropertyIterator properties = node.getProperties();
117  869 while (properties.hasNext()) {
118  781 Property property = properties.nextProperty();
119  781 writeProperty(jsonGenerator, property, node.hasNode(property.getName()));
120    }
121   
122  88 NodeIterator children = node.getNodes();
123   
124  88 JsonArrayBuilder childNodeNames = Json.createArrayBuilder();
125  158 while (children.hasNext()) {
126  70 Node child = children.nextNode();
127  70 writeNode(jsonGenerator, child);
128  70 childNodeNames.add(child.getName());
129    }
130  88 jsonGenerator.write(CHILD_PROPERTY, childNodeNames.build());
131   
132  88 --currentLevel;
133   
134  88 leaveNode(jsonGenerator);
135    } catch (RepositoryException re) {
136  0 currentLevel = 0;
137  0 log.error(re.getMessage());
138    }
139    }
140   
 
141  88 toggle private void enterNode(JsonGenerator jsonGenerator, Node node, int level) throws RepositoryException {
142  88 if (level == 0) { // First node doesn't need to write name.
143  18 jsonGenerator.writeStartObject();
144    } else {
145  70 jsonGenerator.writeStartObject(node.getName());
146    }
147    }
148   
 
149  88 toggle private void leaveNode(JsonGenerator jsonGenerator) {
150  88 jsonGenerator.writeEnd();
151    }
152   
 
153  781 toggle private void writeProperty(JsonGenerator jsonGenerator, Property property, boolean shouldAddPrefix) throws RepositoryException {
154  781 String propertyName = (shouldAddPrefix ? SAME_NAME_SIBLING_PREFIX : "") + property.getName();
155  781 if (property.isMultiple()) {
156  3 jsonGenerator.writeStartArray(propertyName);
157  3 for (Value value : property.getValues()) {
158  9 jsonGenerator.write(getValueString(value));
159    }
160  3 jsonGenerator.writeEnd();
161    } else {
162  778 jsonGenerator.write(propertyName, getValueString(property.getValue()));
163    }
164    }
165   
 
166  88 toggle private void writeSpecialProperties(JsonGenerator jsonGenerator, Node node) throws RepositoryException {
167  88 jsonGenerator.write(NAME_PROPERTY, node.getName());
168  88 jsonGenerator.write(PATH_PROPERTY, node.getPath());
169    }
170   
 
171  787 toggle private String getValueString(Value value) throws RepositoryException {
172  787 switch (value.getType()) {
173  264 case PropertyType.DATE:
174  264 return DateUtil.format(value.getDate().getTime(), null);
175  0 case PropertyType.BINARY:
176  0 return getBinaryString(value);
177  0 case PropertyType.DECIMAL:
178  0 return String.valueOf(value.getDecimal());
179  88 case PropertyType.NAME:
180  0 case PropertyType.URI:
181  88 return value.getString();
182  435 default:
183  435 return PropertyUtil.getValueString(value);
184    }
185    }
186   
187    /**
188    * Gets a string representation of a {@link Value}.
189    * {@link PropertyType#BINARY} types will be base64 encoded.
190    *
191    * @see Base64#encode(byte[])
192    */
 
193  0 toggle private String getBinaryString(Value propertyValue) throws RepositoryException {
194    // Binary values have to be base64 encoded
195  0 byte[] decodedPropertyValue;
196  0 try {
197  0 decodedPropertyValue = Base64.encodeBase64(IOUtils.toByteArray(propertyValue.getBinary().getStream()));
198    } catch (IOException e) {
199  0 throw new RepositoryException(e);
200    }
201  0 return new String(decodedPropertyValue);
202    }
203   
 
204  18 toggle protected void resetCurrentLevel() {
205  18 currentLevel = 0;
206    }
207    }