source: SRUAggregator/trunk/src/main/java/eu/clarin/sru/fcs/aggregator/rest/RestService.java @ 6123

Last change on this file since 6123 was 6123, checked in by emanuel.dima@uni-tuebingen.de, 9 years ago
  1. beta-31: support for query&mode params, and for x-aggregation-context on POST
File size: 11.2 KB
Line 
1package eu.clarin.sru.fcs.aggregator.rest;
2
3import com.fasterxml.jackson.annotation.JsonProperty;
4import com.fasterxml.jackson.core.JsonProcessingException;
5import com.fasterxml.jackson.databind.ObjectMapper;
6import com.fasterxml.jackson.databind.ObjectWriter;
7import eu.clarin.sru.client.SRUVersion;
8import eu.clarin.sru.fcs.aggregator.app.Aggregator;
9import eu.clarin.sru.fcs.aggregator.app.AggregatorConfiguration;
10import eu.clarin.sru.fcs.aggregator.app.AggregatorConfiguration.Params.WeblichtConfig;
11import eu.clarin.sru.fcs.aggregator.scan.Corpora;
12import eu.clarin.sru.fcs.aggregator.scan.Corpus;
13import eu.clarin.sru.fcs.aggregator.scan.Statistics;
14import eu.clarin.sru.fcs.aggregator.search.Result;
15import eu.clarin.sru.fcs.aggregator.search.Search;
16import eu.clarin.sru.fcs.aggregator.util.LanguagesISO693;
17import eu.clarin.sru.fcs.aggregator.search.Exports;
18import java.io.IOException;
19import java.net.URI;
20import java.util.HashMap;
21import java.util.HashSet;
22import java.util.List;
23import java.util.Map;
24import java.util.Set;
25import javax.servlet.ServletContext;
26import javax.servlet.http.HttpServletRequest;
27import javax.ws.rs.FormParam;
28import javax.ws.rs.GET;
29import javax.ws.rs.POST;
30import javax.ws.rs.Path;
31import javax.ws.rs.PathParam;
32import javax.ws.rs.Produces;
33import javax.ws.rs.QueryParam;
34import javax.ws.rs.core.Context;
35import javax.ws.rs.core.MediaType;
36import javax.ws.rs.core.Response;
37import org.slf4j.LoggerFactory;
38
39/**
40 *
41 * @author edima
42 */
43@Produces(MediaType.APPLICATION_JSON)
44@Path("/")
45public class RestService {
46
47        private static final String EXPORT_FILENAME_PREFIX = "ClarinDFederatedContentSearch-";
48        private static final String TCF_MEDIA_TYPE = "text/tcf+xml";
49        private static final String EXCEL_MEDIA_TYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
50        private static final String SEARCH_RESULTS_ENCODING = "UTF-8";
51
52        private static final org.slf4j.Logger log = LoggerFactory.getLogger(RestService.class);
53
54        ObjectWriter ow = new ObjectMapper().writerWithDefaultPrettyPrinter();
55
56        @Context
57        HttpServletRequest request;
58        @Context
59        ServletContext servletContext;
60
61        private String toJson(Object o) throws JsonProcessingException {
62                return ow.writeValueAsString(o);
63        }
64
65        @GET
66        @Path("corpora")
67        public Response getCorpora() throws IOException {
68                List<Corpus> corpora = Aggregator.getInstance().getCorpora().getCorpora();
69                return Response.ok(toJson(corpora)).build();
70        }
71
72        @GET
73        @Path("languages")
74        public Response getLanguages() throws IOException {
75                Set<String> codes = Aggregator.getInstance().getCorpora().getLanguages();
76                log.info("get language codes", codes);
77                Map<String, String> languages = LanguagesISO693.getInstance().getLanguageMap(codes);
78                return Response.ok(toJson(languages)).build();
79        }
80
81        @GET
82        @Path("init")
83        public Response getInit(@Context HttpServletRequest request) throws IOException {
84                log.info("get initial data");
85                final Corpora corpora = Aggregator.getInstance().getCorpora();
86                final Object contextString = request.getSession().getAttribute("x-aggregation-context");
87                final Object query = request.getSession().getAttribute("query");
88                final Object mode = request.getSession().getAttribute("mode");
89                Object j = new HashMap<String, Object>() {
90                        {
91                                if (query != null) {
92                                        put("query", query);
93                                }
94                                if (contextString instanceof String) {
95                                        Object context = new ObjectMapper().readValue((String) contextString, Object.class);
96                                        put("x-aggregation-context", context); // preselected corpora
97                                }
98                                put("corpora", corpora.getCorpora());
99                                put("languages", LanguagesISO693.getInstance().getLanguageMap(corpora.getLanguages()));
100                                put("weblichtLanguages", Aggregator.getInstance().getParams().getWeblichtConfig().getAcceptedTcfLanguages());
101                        }
102                };
103                return Response.ok(toJson(j)).build();
104        }
105
106        @POST
107        @Path("search")
108        public Response postSearch(
109                        @FormParam("query") String query,
110                        @FormParam("firstResultIndex") Integer firstResultIndex,
111                        @FormParam("numberOfResults") Integer numberOfResults,
112                        @FormParam("language") String language,
113                        @FormParam("corporaIds[]") List<String> corporaIds) throws Exception {
114                if (query == null || query.isEmpty()) {
115                        return Response.status(400).entity("'query' parameter expected").build();
116                }
117//              log.info("POST /search corporaIds: " + corporaIds);
118                if (corporaIds == null || corporaIds.isEmpty()) {
119                        return Response.status(400).entity("'corporaIds' parameter expected").build();
120                }
121                List<Corpus> corpora = Aggregator.getInstance().getCorpora().getCorporaByIds(new HashSet<String>(corporaIds));
122                if (corpora == null || corpora.isEmpty()) {
123                        return Response.status(503).entity("No corpora, please wait for the server to finish scanning").build();
124                }
125
126                if (firstResultIndex == null || firstResultIndex < 1) {
127                        firstResultIndex = 1;
128                }
129                if (firstResultIndex > 250) {
130                        firstResultIndex = 250;
131                }
132
133                if (numberOfResults == null || numberOfResults < 10) {
134                        numberOfResults = 10;
135                }
136                if (numberOfResults > 250) {
137                        numberOfResults = 250;
138                }
139
140                Search search = Aggregator.getInstance().startSearch(SRUVersion.VERSION_1_2,
141                                corpora, query, language, firstResultIndex, numberOfResults);
142                if (search == null) {
143                        return Response.status(500).entity("Initiating search failed").build();
144                }
145                URI uri = URI.create("" + search.getId());
146                return Response.created(uri).entity(uri).build();
147        }
148
149        public static class JsonSearch {
150
151                @JsonProperty
152                int inProgress = 0;
153                @JsonProperty
154                List<Result> results;
155
156                public JsonSearch(List<Result> results) {
157                        this.results = results;
158                }
159        }
160
161        @GET
162        @Path("search/{id}")
163        public Response getSearch(@PathParam("id") Long searchId,
164                        @QueryParam("corpusId") String corpusId) throws Exception {
165                Search search = Aggregator.getInstance().getSearchById(searchId);
166                if (search == null) {
167                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
168                }
169
170                JsonSearch js = new JsonSearch(search.getResults(corpusId));
171                for (Result r : js.results) {
172                        if (r.getInProgress()) {
173                                js.inProgress++;
174                        }
175                }
176                return Response.ok(js).build();
177        }
178
179        @POST
180        @Path("search/{id}")
181        public Response postSearchNextResults(@PathParam("id") Long searchId,
182                        @FormParam("corpusId") String corpusId,
183                        @FormParam("numberOfResults") Integer numberOfResults) throws Exception {
184                log.info("POST /search/{id}, corpusId: " + corpusId);
185                if (corpusId == null || corpusId.isEmpty()) {
186                        return Response.status(400).entity("'corpusId' parameter expected").build();
187                }
188                Search search = Aggregator.getInstance().getSearchById(searchId);
189                if (search == null) {
190                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
191                }
192                if (numberOfResults == null || numberOfResults < 10) {
193                        numberOfResults = 10;
194                }
195                if (numberOfResults > 250) {
196                        numberOfResults = 250;
197                }
198
199                boolean ret = search.searchForNextResults(corpusId, numberOfResults);
200                if (ret == false) {
201                        return Response.status(500).entity("Initiating subSearch failed").build();
202                }
203                URI uri = URI.create("" + search.getId());
204                return Response.created(uri).entity(uri).build();
205        }
206
207        @GET
208        @Path("search/{id}/download")
209        public Response downloadSearchResults(@PathParam("id") Long searchId,
210                        @QueryParam("corpusId") String corpusId,
211                        @QueryParam("filterLanguage") String filterLanguage,
212                        @QueryParam("format") String format) throws Exception {
213                Search search = Aggregator.getInstance().getSearchById(searchId);
214                if (search == null) {
215                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
216                }
217                if (filterLanguage == null || filterLanguage.isEmpty()) {
218                        filterLanguage = null;
219                }
220
221                if (format == null || format.trim().isEmpty() || format.trim().equals("text")) {
222                        String text = Exports.getExportText(search.getResults(corpusId), filterLanguage);
223                        return download(text, MediaType.TEXT_PLAIN, search.getQuery() + ".txt");
224                } else if (format.equals("tcf")) {
225                        byte[] bytes = Exports.getExportTCF(
226                                        search.getResults(corpusId), search.getSearchLanguage(), filterLanguage);
227                        return download(bytes, TCF_MEDIA_TYPE, search.getQuery() + ".xml");
228                } else if (format.equals("excel")) {
229                        byte[] bytes = Exports.getExportExcel(search.getResults(corpusId), filterLanguage);
230                        return download(bytes, EXCEL_MEDIA_TYPE, search.getQuery() + ".xls");
231                } else if (format.equals("csv")) {
232                        String csv = Exports.getExportCSV(search.getResults(corpusId), filterLanguage, ";");
233                        return download(csv, MediaType.TEXT_PLAIN, search.getQuery() + ".csv");
234                }
235
236                return Response.status(Response.Status.BAD_REQUEST)
237                                .entity("format parameter must be one of: text, tcf, excel, csv")
238                                .build();
239        }
240
241        Response download(Object entity, String mediaType, String filesuffix) {
242                if (entity == null) {
243                        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
244                                        .entity("error while converting to the export format").build();
245                }
246                String filename = EXPORT_FILENAME_PREFIX + filesuffix;
247                return Response.ok(entity, mediaType)
248                                .header("Content-Disposition", "attachment; filename=\"" + filename + "\"")
249                                .build();
250        }
251
252        @GET
253        @Path("search/{id}/toWeblicht")
254        public Response sendSearchResultsToWeblicht(@PathParam("id") Long searchId,
255                        @QueryParam("filterLanguage") String filterLanguage,
256                        @QueryParam("corpusId") String corpusId) throws Exception {
257                Search search = Aggregator.getInstance().getSearchById(searchId);
258                if (search == null) {
259                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
260                }
261                if (filterLanguage == null || filterLanguage.isEmpty()) {
262                        filterLanguage = null;
263                }
264
265                String url = null;
266                byte[] bytes = Exports.getExportTCF(
267                                search.getResults(corpusId), search.getSearchLanguage(), filterLanguage);
268                if (bytes != null) {
269                        url = DataTransfer.uploadToDropOff(bytes, "text/tcf+xml", ".tcf");
270                }
271
272                WeblichtConfig weblicht = Aggregator.getInstance().getParams().getWeblichtConfig();
273                URI weblichtUri = new URI(weblicht.getUrl() + url);
274                return url == null
275                                ? Response.status(503).entity("error while exporting to weblicht").build()
276                                : Response.seeOther(weblichtUri).entity(weblichtUri).build();
277        }
278
279        @GET
280        @Path("statistics")
281        public Response getStatistics() throws IOException {
282                final Statistics scan = Aggregator.getInstance().getScanStatistics();
283                final Statistics search = Aggregator.getInstance().getSearchStatistics();
284                final AggregatorConfiguration.Params params = Aggregator.getInstance().getParams();
285
286                Object j = new HashMap<String, Object>() {
287                        {
288                                put("Last Scan", new HashMap<String, Object>() {
289                                        {
290                                                put("maxConcurrentScanRequestsPerEndpoint",
291                                                                Aggregator.getInstance().getParams().getSCAN_MAX_CONCURRENT_REQUESTS_PER_ENDPOINT());
292                                                put("timeout", params.getENDPOINTS_SCAN_TIMEOUT_MS() / 1000.);
293                                                put("isScan", true);
294                                                put("institutions", scan.getInstitutions());
295                                                put("date", scan.getDate());
296                                        }
297                                });
298                                put("Recent Searches", new HashMap<String, Object>() {
299                                        {
300                                                put("maxConcurrentSearchRequestsPerEndpoint",
301                                                                Aggregator.getInstance().getParams().getSEARCH_MAX_CONCURRENT_REQUESTS_PER_ENDPOINT());
302                                                put("timeout", params.getENDPOINTS_SEARCH_TIMEOUT_MS() / 1000.);
303                                                put("isScan", false);
304                                                put("institutions", search.getInstitutions());
305                                                put("date", scan.getDate());
306                                        }
307                                });
308                        }
309                };
310                return Response.ok(toJson(j)).build();
311        }
312
313}
Note: See TracBrowser for help on using the repository browser.