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.providers;
21  
22  import com.fasterxml.jackson.core.JsonParseException;
23  import com.fasterxml.jackson.core.type.TypeReference;
24  import com.fasterxml.jackson.databind.JsonMappingException;
25  import com.fasterxml.jackson.databind.ObjectReader;
26  import com.fasterxml.jackson.databind.ObjectWriter;
27  import com.fasterxml.jackson.dataformat.csv.CsvGenerator;
28  import com.fasterxml.jackson.dataformat.csv.CsvMapper;
29  import com.fasterxml.jackson.dataformat.csv.CsvParser;
30  import com.fasterxml.jackson.dataformat.csv.CsvSchema;
31  import eu.ehri.extension.base.AbstractResource;
32  import eu.ehri.extension.errors.WebDeserializationError;
33  import eu.ehri.project.utils.Table;
34  import eu.ehri.project.exceptions.DeserializationError;
35  
36  import javax.ws.rs.Consumes;
37  import javax.ws.rs.Produces;
38  import javax.ws.rs.WebApplicationException;
39  import javax.ws.rs.core.MediaType;
40  import javax.ws.rs.core.MultivaluedMap;
41  import javax.ws.rs.ext.MessageBodyReader;
42  import javax.ws.rs.ext.MessageBodyWriter;
43  import javax.ws.rs.ext.Provider;
44  import java.io.IOException;
45  import java.io.InputStream;
46  import java.io.OutputStream;
47  import java.lang.annotation.Annotation;
48  import java.lang.reflect.Type;
49  import java.util.List;
50  
51  /**
52   * Provider for row/column data.
53   * <p>
54   * TODO: Handle CSV headers
55   */
56  @Provider
57  @Produces({MediaType.APPLICATION_JSON, AbstractResource.CSV_MEDIA_TYPE})
58  @Consumes({MediaType.APPLICATION_JSON, AbstractResource.CSV_MEDIA_TYPE})
59  public class TableProvider implements MessageBodyWriter<Table>, MessageBodyReader<Table>, JsonMessageBodyHandler {
60  
61      private static CsvMapper csvMapper = new CsvMapper()
62              .enable(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
63              .enable(CsvParser.Feature.WRAP_AS_ARRAY);
64      private static CsvSchema csvSchema = csvMapper.schemaFor(List.class);
65  
66      private static TypeReference<List<List<String>>> typeRef = new TypeReference<List<List<String>>>() {
67      };
68  
69      @Override
70      public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
71          return Table.class.equals(type);
72      }
73  
74      @Override
75      public long getSize(Table table, Class<?> aClass, Type type, Annotation[] annotations,
76              MediaType mediaType) {
77          return -1L;
78      }
79  
80      @Override
81      public void writeTo(Table table,
82              Class<?> aClass, Type type, Annotation[] annotations,
83              MediaType mediaType, MultivaluedMap<String, Object> headers,
84              OutputStream outputStream) throws IOException, WebApplicationException {
85          ObjectWriter writer = mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)
86                  ? mapper.writer()
87                  : csvMapper.writer(csvSchema.withoutHeader());
88          writer.writeValue(outputStream, table.rows());
89      }
90  
91      @Override
92      public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
93          return Table.class.equals(type);
94      }
95  
96      @Override
97      public Table readFrom(Class<Table> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
98          try {
99              ObjectReader reader = mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)
100                     ? mapper.readerFor(typeRef)
101                     : csvMapper.readerFor(typeRef).with(csvSchema.withoutHeader());
102             return Table.of(reader.readValue(entityStream));
103         } catch (JsonMappingException | JsonParseException e) {
104             throw new WebDeserializationError(new DeserializationError(
105                     "Deserialization error for media type: " + mediaType, e));
106         }
107     }
108 }