Clover icon

Magnolia REST Services 1.1

  1. Project Clover database Thu Aug 13 2015 19:10:59 CEST
  2. Package info.magnolia.rest.service.property.v1

File PropertyEndpoint.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

16
65
5
1
295
193
17
0.26
13
5
3.4

Classes

Class Line # Actions
PropertyEndpoint 80 65 0% 17 0
1.0100%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /**
2    * This file Copyright (c) 2012-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.rest.service.property.v1;
35   
36    import info.magnolia.cms.util.ExclusiveWrite;
37    import info.magnolia.cms.util.PathUtil;
38    import info.magnolia.context.MgnlContext;
39    import info.magnolia.rest.AbstractEndpoint;
40    import info.magnolia.rest.service.node.v1.RepositoryMarshaller;
41    import info.magnolia.rest.service.node.v1.RepositoryProperty;
42    import info.magnolia.rest.service.property.definition.PropertyEndpointDefinition;
43   
44    import java.util.List;
45   
46    import javax.inject.Inject;
47    import javax.jcr.Node;
48    import javax.jcr.Property;
49    import javax.jcr.PropertyType;
50    import javax.jcr.RepositoryException;
51    import javax.jcr.Session;
52    import javax.ws.rs.DELETE;
53    import javax.ws.rs.DefaultValue;
54    import javax.ws.rs.GET;
55    import javax.ws.rs.POST;
56    import javax.ws.rs.PUT;
57    import javax.ws.rs.Path;
58    import javax.ws.rs.PathParam;
59    import javax.ws.rs.Produces;
60    import javax.ws.rs.QueryParam;
61    import javax.ws.rs.core.MediaType;
62    import javax.ws.rs.core.Response;
63   
64    import org.apache.commons.lang.StringUtils;
65    import org.slf4j.Logger;
66    import org.slf4j.LoggerFactory;
67   
68    import com.wordnik.swagger.annotations.Api;
69    import com.wordnik.swagger.annotations.ApiOperation;
70    import com.wordnik.swagger.annotations.ApiResponse;
71    import com.wordnik.swagger.annotations.ApiResponses;
72   
73    /**
74    * Endpoint for accessing and manipulating properties.
75    *
76    * @param <D> The endpoint definition
77    */
78    @Api(value = "/properties/v1", description = "The properties API")
79    @Path("/properties/v1")
 
80    public class PropertyEndpoint<D extends PropertyEndpointDefinition> extends AbstractEndpoint<D> {
81   
82    private static final String STATUS_MESSAGE_OK = "OK";
83    private static final String STATUS_MESSAGE_PROPERTY_ALREADY_EXISTS = "Property already exists";
84    private static final String STATUS_MESSAGE_UNAUTHORIZED = "Unauthorized";
85    private static final String STATUS_MESSAGE_ACCESS_DENIED = "Access denied";
86    private static final String STATUS_MESSAGE_NODE_NOT_FOUND = "Node not found";
87    private static final String STATUS_MESSAGE_PROPERTY_NOT_FOUND = "Property not found";
88    private static final String STATUS_MESSAGE_ERROR_OCCURRED = "Error occurred";
89   
90    private final Logger log = LoggerFactory.getLogger(getClass());
91   
92    private RepositoryMarshaller marshaller = new RepositoryMarshaller();
93   
 
94  22 toggle @Inject
95    public PropertyEndpoint(final D endpointDefinition) {
96  22 super(endpointDefinition);
97    }
98   
99    /**
100    * Returns the string representation of a property's value.
101    */
 
102  3 toggle @GET
103    @Path("/{workspace}{path:(/.+)?}")
104    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
105    @ApiOperation(value = "Get a property from a node", notes = "Reads a property from a node")
106    @ApiResponses(value = {
107    @ApiResponse(code = 200, message = STATUS_MESSAGE_OK, response = RepositoryProperty.class),
108    @ApiResponse(code = 401, message = STATUS_MESSAGE_UNAUTHORIZED),
109    @ApiResponse(code = 404, message = STATUS_MESSAGE_PROPERTY_NOT_FOUND),
110    @ApiResponse(code = 500, message = STATUS_MESSAGE_ERROR_OCCURRED)
111    })
112    public Response readProperty(
113    @PathParam("workspace") String workspaceName,
114    @PathParam("path") @DefaultValue("/") String path) throws RepositoryException {
115   
116  3 final String absPath = StringUtils.defaultIfEmpty(path, "/");
117   
118  3 final Session session = MgnlContext.getJCRSession(workspaceName);
119   
120  3 if (!session.propertyExists(absPath)) {
121  1 return Response.status(Response.Status.NOT_FOUND).build();
122    }
123   
124  2 final Property property = session.getProperty(absPath);
125   
126  2 RepositoryProperty response = marshaller.marshallProperty(property);
127   
128  2 log.debug("Returned property [{}]", property.getParent().getPath());
129   
130  2 return Response.ok().entity(response).build();
131    }
132   
133    /**
134    * Adds a property to a node.
135    */
 
136  9 toggle @PUT
137    @Path("/{workspace}{path:(/.+)?}")
138    @ApiOperation(value = "Add property on a node", notes = "Adds a property on a node")
139    @ApiResponses(value = {
140    @ApiResponse(code = 200, message = STATUS_MESSAGE_OK),
141    @ApiResponse(code = 400, message = STATUS_MESSAGE_PROPERTY_ALREADY_EXISTS),
142    @ApiResponse(code = 401, message = STATUS_MESSAGE_UNAUTHORIZED),
143    @ApiResponse(code = 403, message = STATUS_MESSAGE_ACCESS_DENIED),
144    @ApiResponse(code = 404, message = STATUS_MESSAGE_NODE_NOT_FOUND),
145    @ApiResponse(code = 500, message = STATUS_MESSAGE_ERROR_OCCURRED)
146    })
147    public Response createProperty(
148    @PathParam("workspace") String workspaceName,
149    @PathParam("path") @DefaultValue("/") String parentPath,
150    @QueryParam("name") String name,
151    @QueryParam("value") List<String> valueStrings,
152    @QueryParam("type") @DefaultValue(PropertyType.TYPENAME_STRING) String typeString,
153    @QueryParam("multiple") @DefaultValue("false") boolean multiple) throws RepositoryException {
154   
155  9 if (!multiple && valueStrings.size() != 1) {
156  2 return Response.status(Response.Status.BAD_REQUEST).build();
157    }
158   
159  7 try {
160  7 PropertyType.valueFromName(typeString);
161    } catch (IllegalArgumentException e) {
162  1 return Response.status(Response.Status.BAD_REQUEST).build();
163    }
164   
165  6 final String parentAbsPath = StringUtils.defaultIfEmpty(parentPath, "/");
166   
167  6 final Session session = MgnlContext.getJCRSession(workspaceName);
168   
169  6 if (!session.nodeExists(parentAbsPath)) {
170  1 return Response.status(Response.Status.NOT_FOUND).build();
171    }
172   
173  5 final Node node = session.getNode(parentAbsPath);
174   
175  5 if (node.hasProperty(name)) {
176  1 return Response.status(Response.Status.BAD_REQUEST).build();
177    }
178   
179  4 RepositoryProperty property = new RepositoryProperty();
180  4 property.setName(name);
181  4 property.setMultiple(multiple);
182  4 property.setType(typeString);
183  4 property.getValues().addAll(valueStrings);
184   
185  4 marshaller.unmarshallProperty(node, property);
186   
187  4 synchronized (ExclusiveWrite.getInstance()) {
188  4 session.save();
189    }
190   
191  4 log.debug("Added property [{}]", PathUtil.createPath(parentAbsPath, name));
192   
193  4 return Response.ok().build();
194    }
195   
196    /**
197    * Sets the value of an existing property.
198    */
 
199  8 toggle @POST
200    @Path("/{workspace}{path:(/.+)?}")
201    @ApiOperation(value = "Update property on a node", notes = "Updates a property on a node")
202    @ApiResponses(value = {
203    @ApiResponse(code = 200, message = STATUS_MESSAGE_OK),
204    @ApiResponse(code = 401, message = STATUS_MESSAGE_UNAUTHORIZED),
205    @ApiResponse(code = 403, message = STATUS_MESSAGE_ACCESS_DENIED),
206    @ApiResponse(code = 404, message = STATUS_MESSAGE_PROPERTY_NOT_FOUND),
207    @ApiResponse(code = 500, message = STATUS_MESSAGE_ERROR_OCCURRED)
208    })
209    public Response updateProperty(
210    @PathParam("workspace") String workspaceName,
211    @PathParam("path") @DefaultValue("/") String path,
212    @QueryParam("value") List<String> valueStrings,
213    @QueryParam("type") @DefaultValue(PropertyType.TYPENAME_STRING) String typeString,
214    @QueryParam("multiple") @DefaultValue("false") boolean multiple) throws RepositoryException {
215   
216  8 if (!multiple && valueStrings.size() != 1) {
217  2 return Response.status(Response.Status.BAD_REQUEST).build();
218    }
219   
220  6 try {
221  6 PropertyType.valueFromName(typeString);
222    } catch (IllegalArgumentException e) {
223  1 return Response.status(Response.Status.BAD_REQUEST).build();
224    }
225   
226  5 final String absPath = StringUtils.defaultIfEmpty(path, "/");
227  5 final String name = StringUtils.substringAfterLast(absPath, "/");
228  5 String parentPath = StringUtils.substringBeforeLast(absPath, "/");
229  5 if (parentPath.isEmpty()) {
230  1 parentPath = "/";
231    }
232   
233  5 final Session session = MgnlContext.getJCRSession(workspaceName);
234   
235  5 if (!session.propertyExists(absPath)) {
236  1 return Response.status(Response.Status.NOT_FOUND).build();
237    }
238   
239  4 final Node node = session.getNode(parentPath);
240   
241  4 RepositoryProperty property = new RepositoryProperty();
242  4 property.setName(name);
243  4 property.setMultiple(multiple);
244  4 property.setType(typeString);
245  4 property.getValues().addAll(valueStrings);
246   
247  4 marshaller.unmarshallProperty(node, property);
248   
249  4 synchronized (ExclusiveWrite.getInstance()) {
250  4 session.save();
251    }
252   
253  4 log.debug("Updated property [{}]", path);
254   
255  4 return Response.ok().build();
256    }
257   
258    /**
259    * Deletes a property.
260    */
 
261  2 toggle @DELETE
262    @Path("/{workspace}{path:(/.+)?}")
263    @ApiOperation(value = "Delete a property", notes = "Deletes a property")
264    @ApiResponses(value = {
265    @ApiResponse(code = 200, message = STATUS_MESSAGE_OK),
266    @ApiResponse(code = 401, message = STATUS_MESSAGE_UNAUTHORIZED),
267    @ApiResponse(code = 403, message = STATUS_MESSAGE_ACCESS_DENIED),
268    @ApiResponse(code = 404, message = STATUS_MESSAGE_PROPERTY_NOT_FOUND),
269    @ApiResponse(code = 500, message = STATUS_MESSAGE_ERROR_OCCURRED)
270    })
271    public Response deleteProperty(
272    @PathParam("workspace") String workspaceName,
273    @PathParam("path") @DefaultValue("/") String path) throws RepositoryException {
274   
275  2 final String absPath = StringUtils.defaultIfEmpty(path, "/");
276   
277  2 final Session session = MgnlContext.getJCRSession(workspaceName);
278   
279  2 if (!session.propertyExists(absPath)) {
280  1 return Response.status(Response.Status.NOT_FOUND).build();
281    }
282   
283  1 final Property property = session.getProperty(absPath);
284   
285  1 property.remove();
286   
287  1 synchronized (ExclusiveWrite.getInstance()) {
288  1 session.save();
289    }
290   
291  1 log.debug("Deleted property [{}]", absPath);
292   
293  1 return Response.ok().build();
294    }
295    }