View Javadoc

1   /*
2    * Copyright 2015 Data Archiving and Networked Services (an institute of
3    * Koninklijke Nederlandse Akademie van Wetenschappen), King's College London,
4    * Georg-August-Universitaet Goettingen Stiftung Oeffentlichen Rechts
5    *
6    * Licensed under the EUPL, Version 1.1 or – as soon they will be approved by
7    * the European Commission - subsequent versions of the EUPL (the "Licence");
8    * You may not use this work except in compliance with the Licence.
9    * You may obtain a copy of the Licence at:
10   *
11   * https://joinup.ec.europa.eu/software/page/eupl
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the Licence is distributed on an "AS IS" basis,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the Licence for the specific language governing
17   * permissions and limitations under the Licence.
18   */
19  
20  package eu.ehri.extension;
21  
22  import eu.ehri.extension.base.AbstractAccessibleResource;
23  import eu.ehri.extension.base.AbstractResource;
24  import eu.ehri.extension.base.DeleteResource;
25  import eu.ehri.extension.base.GetResource;
26  import eu.ehri.extension.base.ListResource;
27  import eu.ehri.extension.base.ParentResource;
28  import eu.ehri.extension.base.UpdateResource;
29  import eu.ehri.project.core.Tx;
30  import eu.ehri.project.definitions.Entities;
31  import eu.ehri.project.exceptions.AccessDenied;
32  import eu.ehri.project.exceptions.DeserializationError;
33  import eu.ehri.project.exceptions.ItemNotFound;
34  import eu.ehri.project.exceptions.PermissionDenied;
35  import eu.ehri.project.exceptions.ValidationError;
36  import eu.ehri.project.models.cvoc.Concept;
37  import eu.ehri.project.persistence.Bundle;
38  import org.neo4j.graphdb.GraphDatabaseService;
39  
40  import javax.ws.rs.Consumes;
41  import javax.ws.rs.DELETE;
42  import javax.ws.rs.DefaultValue;
43  import javax.ws.rs.GET;
44  import javax.ws.rs.POST;
45  import javax.ws.rs.PUT;
46  import javax.ws.rs.Path;
47  import javax.ws.rs.PathParam;
48  import javax.ws.rs.Produces;
49  import javax.ws.rs.QueryParam;
50  import javax.ws.rs.core.Context;
51  import javax.ws.rs.core.MediaType;
52  import javax.ws.rs.core.Response;
53  import java.util.List;
54  
55  /**
56   * Provides a web service interface for the Concept model. Note that the concept
57   * creation endpoint is part of the VocabularyResource and creation without a
58   * Vocabulary is not possible via this API.
59   */
60  @Path(AbstractResource.RESOURCE_ENDPOINT_PREFIX + "/" + Entities.CVOC_CONCEPT)
61  public class CvocConceptResource
62          extends AbstractAccessibleResource<Concept>
63          implements ParentResource, GetResource, ListResource, UpdateResource, DeleteResource {
64  
65      public CvocConceptResource(@Context GraphDatabaseService database) {
66          super(database, Concept.class);
67      }
68  
69      @GET
70      @Produces(MediaType.APPLICATION_JSON)
71      @Path("{id:[^/]+}")
72      @Override
73      public Response get(@PathParam("id") String id) throws ItemNotFound {
74          return getItem(id);
75      }
76  
77      @GET
78      @Produces(MediaType.APPLICATION_JSON)
79      @Override
80      public Response list() {
81          return listItems();
82      }
83  
84      @PUT
85      @Consumes(MediaType.APPLICATION_JSON)
86      @Produces(MediaType.APPLICATION_JSON)
87      @Path("{id:[^/]+}")
88      @Override
89      public Response update(@PathParam("id") String id, Bundle bundle)
90              throws PermissionDenied, ValidationError,
91              DeserializationError, ItemNotFound {
92          try (final Tx tx = beginTx()) {
93              Response item = updateItem(id, bundle);
94              tx.success();
95              return item;
96          }
97      }
98  
99      @DELETE
100     @Path("{id:[^/]+}")
101     @Override
102     public void delete(@PathParam("id") String id)
103             throws PermissionDenied, ItemNotFound, ValidationError {
104         try (final Tx tx = beginTx()) {
105             deleteItem(id);
106             tx.success();
107         }
108     }
109 
110     @GET
111     @Produces(MediaType.APPLICATION_JSON)
112     @Path("{id:[^/]+}/list")
113     @Override
114     public Response listChildren(@PathParam("id") String id,
115             @QueryParam(ALL_PARAM) @DefaultValue("false") boolean all) throws ItemNotFound {
116         try (final Tx tx = beginTx()) {
117             Concept concept = api().detail(id, cls);
118             Response response = streamingPage(() -> getQuery()
119                     .page(concept.getNarrowerConcepts(), Concept.class));
120             tx.success();
121             return response;
122         }
123     }
124 
125     @POST
126     @Consumes(MediaType.APPLICATION_JSON)
127     @Produces(MediaType.APPLICATION_JSON)
128     @Path("{id:[^/]+}")
129     @Override
130     public Response createChild(@PathParam("id") String id,
131             Bundle bundle, @QueryParam(ACCESSOR_PARAM) List<String> accessors)
132             throws PermissionDenied, ValidationError,
133             DeserializationError, ItemNotFound {
134         try (final Tx tx = beginTx()) {
135             final Concept parent = api().detail(id, cls);
136             Response item = createItem(bundle, accessors, concept -> {
137                 parent.addNarrowerConcept(concept);
138                 concept.setVocabulary(parent.getVocabulary());
139             }, api().withScope(parent.getVocabulary()), cls);
140             tx.success();
141             return item;
142         }
143     }
144 
145     /**
146      * Add an existing concept to the list of 'narrower' relations.
147      *
148      * @param id       the item ID
149      * @param narrower the narrower item IDs
150      */
151     @POST
152     @Path("{id:[^/]+}/narrower")
153     public Response addNarrowerCvocConcept(
154             @PathParam("id") String id,
155             @QueryParam(ID_PARAM) List<String> narrower)
156             throws AccessDenied, PermissionDenied, ItemNotFound {
157         try (final Tx tx = beginTx()) {
158             Response item = single(api().concepts()
159                     .addNarrowerConcepts(id, narrower));
160             tx.success();
161             return item;
162         }
163     }
164 
165     /**
166      * Remove a narrower relationship between two concepts.
167      *
168      * @param id       the item ID
169      * @param narrower the narrower item IDs
170      */
171     @DELETE
172     @Path("{id:[^/]+}/narrower")
173     public Response removeNarrowerCvocConcept(
174             @PathParam("id") String id,
175             @QueryParam(ID_PARAM) List<String> narrower)
176             throws PermissionDenied, AccessDenied, ItemNotFound {
177         try (final Tx tx = beginTx()) {
178             Response item = single(api().concepts()
179                     .removeNarrowerConcepts(id, narrower));
180             tx.success();
181             return item;
182         }
183     }
184 
185     /**
186      * List broader concepts.
187      *
188      * @param id The item ID
189      * @return A list of broader resources
190      */
191     @GET
192     @Produces(MediaType.APPLICATION_JSON)
193     @Path("{id:[^/]+}/broader")
194     public Response getCvocBroaderConcepts(@PathParam("id") String id)
195             throws ItemNotFound, AccessDenied {
196         try (final Tx tx = beginTx()) {
197             Concept concept = api().detail(id, cls);
198             Response response = streamingList(concept::getBroaderConcepts);
199             tx.success();
200             return response;
201         }
202     }
203 
204     /**
205      * List concepts related to another concept.
206      *
207      * @param id The item ID
208      * @return A list of related resources
209      */
210     @GET
211     @Produces(MediaType.APPLICATION_JSON)
212     @Path("{id:[^/]+}/related")
213     public Response getCvocRelatedConcepts(@PathParam("id") String id) throws ItemNotFound {
214         try (final Tx tx = beginTx()) {
215             Concept concept = api().detail(id, cls);
216             Response response = streamingList(concept::getRelatedConcepts);
217             tx.success();
218             return response;
219         }
220     }
221 
222     /**
223      * List concepts related to another concept. This is the
224      * &quot;reverse&quot; form of the &quot;/related&quot;
225      * method.
226      *
227      * @param id The item ID
228      * @return A list of related resources
229      */
230     @GET
231     @Produces(MediaType.APPLICATION_JSON)
232     @Path("{id:[^/]+}/relatedBy")
233     public Response getCvocRelatedByConcepts(@PathParam("id") String id) throws ItemNotFound {
234         try (final Tx tx = beginTx()) {
235             Concept concept = api().detail(id, cls);
236             Response response = streamingList(concept::getRelatedByConcepts);
237             tx.success();
238             return response;
239         }
240     }
241 
242     /**
243      * Add a relation by creating the 'related' edge between the two <em>existing</em>
244      * items.
245      *
246      * @param id      the item ID
247      * @param related the related item IDs
248      */
249     @POST
250     @Path("{id:[^/]+}/related")
251     public Response addRelatedCvocConcept(
252             @PathParam("id") String id,
253             @QueryParam(ID_PARAM) List<String> related)
254             throws AccessDenied, PermissionDenied, ItemNotFound {
255         try (final Tx tx = beginTx()) {
256             Response item = single(api().concepts()
257                     .addRelatedConcepts(id, related));
258             tx.success();
259             return item;
260         }
261     }
262 
263     /**
264      * Remove a relation by deleting the edge, not the vertex of the related
265      * concept.
266      *
267      * @param id      the item ID
268      * @param related the related item ID
269      */
270     @DELETE
271     @Path("{id:[^/]+}/related")
272     public Response removeRelatedCvocConcept(
273             @PathParam("id") String id,
274             @QueryParam(ID_PARAM) List<String> related)
275             throws AccessDenied, PermissionDenied, ItemNotFound {
276         try (final Tx tx = beginTx()) {
277             Response item = single(api().concepts()
278                     .removeRelatedConcepts(id, related));
279             tx.success();
280             return item;
281         }
282     }
283 }