Clover icon

Magnolia REST Services 2.0-alpha2

  1. Project Clover database Tue Oct 10 2017 14:50: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
296
193
17
0.26
13
5
3.4

Classes

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