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.CreateResource;
25  import eu.ehri.extension.base.DeleteResource;
26  import eu.ehri.extension.base.GetResource;
27  import eu.ehri.extension.base.ListResource;
28  import eu.ehri.extension.base.ParentResource;
29  import eu.ehri.extension.base.UpdateResource;
30  import eu.ehri.project.api.Api;
31  import eu.ehri.project.core.Tx;
32  import eu.ehri.project.definitions.Entities;
33  import eu.ehri.project.definitions.EventTypes;
34  import eu.ehri.project.exceptions.AccessDenied;
35  import eu.ehri.project.exceptions.DeserializationError;
36  import eu.ehri.project.exceptions.ItemNotFound;
37  import eu.ehri.project.exceptions.PermissionDenied;
38  import eu.ehri.project.exceptions.SerializationError;
39  import eu.ehri.project.exceptions.ValidationError;
40  import eu.ehri.project.exporters.cvoc.JenaSkosExporter;
41  import eu.ehri.project.importers.cvoc.SkosRDFVocabulary;
42  import eu.ehri.project.models.base.Actioner;
43  import eu.ehri.project.models.cvoc.Concept;
44  import eu.ehri.project.models.cvoc.Vocabulary;
45  import eu.ehri.project.persistence.ActionManager;
46  import eu.ehri.project.persistence.Bundle;
47  import org.apache.jena.rdf.model.Model;
48  import org.neo4j.graphdb.GraphDatabaseService;
49  
50  import javax.ws.rs.Consumes;
51  import javax.ws.rs.DELETE;
52  import javax.ws.rs.DefaultValue;
53  import javax.ws.rs.GET;
54  import javax.ws.rs.POST;
55  import javax.ws.rs.PUT;
56  import javax.ws.rs.Path;
57  import javax.ws.rs.PathParam;
58  import javax.ws.rs.Produces;
59  import javax.ws.rs.QueryParam;
60  import javax.ws.rs.core.Context;
61  import javax.ws.rs.core.MediaType;
62  import javax.ws.rs.core.Response;
63  import javax.ws.rs.core.StreamingOutput;
64  import java.io.IOException;
65  import java.util.List;
66  
67  /**
68   * Provides a web service interface for the Vocabulary model. Vocabularies are
69   * containers for Concepts.
70   */
71  @Path(AbstractResource.RESOURCE_ENDPOINT_PREFIX + "/" + Entities.CVOC_VOCABULARY)
72  public class VocabularyResource extends AbstractAccessibleResource<Vocabulary>
73          implements GetResource, ListResource, DeleteResource, CreateResource, UpdateResource, ParentResource {
74  
75      public VocabularyResource(@Context GraphDatabaseService database) {
76          super(database, Vocabulary.class);
77      }
78  
79      @GET
80      @Produces(MediaType.APPLICATION_JSON)
81      @Path("{id:[^/]+}")
82      @Override
83      public Response get(@PathParam("id") String id) throws ItemNotFound {
84          return getItem(id);
85      }
86  
87      @GET
88      @Produces(MediaType.APPLICATION_JSON)
89      @Override
90      public Response list() {
91          return listItems();
92      }
93  
94      @GET
95      @Produces(MediaType.APPLICATION_JSON)
96      @Path("{id:[^/]+}/list")
97      @Override
98      public Response listChildren(
99              @PathParam("id") String id,
100             @QueryParam(ALL_PARAM) @DefaultValue("false") boolean all) throws ItemNotFound {
101         try (final Tx tx = beginTx()) {
102             Vocabulary vocabulary = api().detail(id, cls);
103             Response response = streamingPage(() -> getQuery()
104                     .page(vocabulary.getConcepts(), Concept.class));
105             tx.success();
106             return response;
107         }
108     }
109 
110     @POST
111     @Consumes(MediaType.APPLICATION_JSON)
112     @Produces(MediaType.APPLICATION_JSON)
113     @Override
114     public Response create(Bundle bundle,
115             @QueryParam(ACCESSOR_PARAM) List<String> accessors)
116             throws PermissionDenied, ValidationError, DeserializationError {
117         try (final Tx tx = beginTx()) {
118             Response item = createItem(bundle, accessors);
119             tx.success();
120             return item;
121         }
122     }
123 
124     @PUT
125     @Consumes(MediaType.APPLICATION_JSON)
126     @Produces(MediaType.APPLICATION_JSON)
127     @Path("{id:[^/]+}")
128     @Override
129     public Response update(@PathParam("id") String id, Bundle bundle)
130             throws PermissionDenied, ValidationError,
131             DeserializationError, ItemNotFound {
132         try (final Tx tx = beginTx()) {
133             Response item = updateItem(id, bundle);
134             tx.success();
135             return item;
136         }
137     }
138 
139     @DELETE
140     @Path("{id:[^/]+}")
141     @Override
142     public void delete(@PathParam("id") String id)
143             throws PermissionDenied, ItemNotFound, ValidationError {
144         try (final Tx tx = beginTx()) {
145             deleteItem(id);
146             tx.success();
147         }
148     }
149 
150     @DELETE
151     @Path("{id:[^/]+}/all")
152     public void deleteAllVocabularyConcepts(@PathParam("id") String id)
153             throws ItemNotFound, AccessDenied, PermissionDenied {
154         try (final Tx tx = beginTx()) {
155             Actioner user = getCurrentActioner();
156             Api api = api().enableLogging(false);
157             Vocabulary vocabulary = api.detail(id, cls);
158             ActionManager actionManager = api.actionManager().setScope(vocabulary);
159             Iterable<Concept> concepts = vocabulary.getConcepts();
160             if (concepts.iterator().hasNext()) {
161                 ActionManager.EventContext context = actionManager
162                         .newEventContext(user, EventTypes.deletion, getLogMessage());
163                 for (Concept concept : concepts) {
164                     context.addSubjects(concept);
165                     context.createVersion(concept);
166                 }
167                 context.commit();
168                 for (Concept concept : concepts) {
169                     api.delete(concept.getId());
170                 }
171             }
172             tx.success();
173         } catch (SerializationError | ValidationError e) {
174             throw new RuntimeException(e);
175         }
176     }
177 
178     @POST
179     @Consumes(MediaType.APPLICATION_JSON)
180     @Produces(MediaType.APPLICATION_JSON)
181     @Path("{id:[^/]+}")
182     @Override
183     public Response createChild(@PathParam("id") String id,
184             Bundle bundle, @QueryParam(ACCESSOR_PARAM) List<String> accessors)
185             throws PermissionDenied, ValidationError,
186             DeserializationError, ItemNotFound {
187         try (final Tx tx = beginTx()) {
188             final Vocabulary vocabulary = api().detail(id, cls);
189             Response item = createItem(bundle, accessors,
190                     concept -> concept.setVocabulary(vocabulary),
191                     api().withScope(vocabulary), Concept.class);
192             tx.success();
193             return item;
194         }
195     }
196 
197     /**
198      * Export the given vocabulary as SKOS.
199      *
200      * @param id      the vocabulary id
201      * @param format  the RDF format. Can be one of: RDF/XML, N3, TTL
202      * @param baseUri the base URI for exported items
203      * @return a SKOS vocabulary
204      */
205     @GET
206     @Path("{id:[^/]+}/export")
207     @Produces({TURTLE_MIMETYPE, RDF_XML_MIMETYPE, N3_MIMETYPE})
208     public Response exportSkos(@PathParam("id") String id,
209             final @QueryParam("format") String format,
210             final @QueryParam("baseUri") String baseUri)
211             throws IOException, ItemNotFound {
212         final String rdfFormat = getRdfFormat(format, "TTL");
213         final String base = baseUri == null ? SkosRDFVocabulary.DEFAULT_BASE_URI : baseUri;
214         final MediaType mediaType = MediaType.valueOf(RDF_MIMETYPE_FORMATS
215                 .inverse().get(rdfFormat));
216         try (final Tx tx = beginTx()) {
217             final Vocabulary vocabulary = api().detail(id, cls);
218             final JenaSkosExporter skosImporter = new JenaSkosExporter(graph, vocabulary);
219             final Model model = skosImporter.export(base);
220             tx.success();
221             return Response.ok((StreamingOutput) outputStream ->
222                     model.getWriter(rdfFormat).write(model, outputStream, base))
223                     .type(mediaType + "; charset=utf-8").build();
224         }
225     }
226 }