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

Last change on this file since 6092 was 6092, checked in by emanuel.dima@uni-tuebingen.de, 9 years ago
  1. beta-27: more results, bug fixes
File size: 10.6 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() throws IOException {
84                log.info("get initial data");
85                final Corpora corpora = Aggregator.getInstance().getCorpora();
86                Object j = new HashMap<String, Object>() {
87                        {
88                                put("corpora", corpora.getCorpora());
89                                put("languages", LanguagesISO693.getInstance().getLanguageMap(corpora.getLanguages()));
90                                put("weblichtLanguages", Aggregator.getInstance().getParams().getWeblichtConfig().getAcceptedTcfLanguages());
91                        }
92                };
93                return Response.ok(toJson(j)).build();
94        }
95
96        @POST
97        @Path("search")
98        public Response postSearch(
99                        @FormParam("query") String query,
100                        @FormParam("firstResultIndex") Integer firstResultIndex,
101                        @FormParam("numberOfResults") Integer numberOfResults,
102                        @FormParam("language") String language,
103                        @FormParam("corporaIds[]") List<String> corporaIds) throws Exception {
104                if (query == null || query.isEmpty()) {
105                        return Response.status(400).entity("'query' parameter expected").build();
106                }
107//              log.info("POST /search corporaIds: " + corporaIds);
108                if (corporaIds == null || corporaIds.isEmpty()) {
109                        return Response.status(400).entity("'corporaIds' parameter expected").build();
110                }
111                List<Corpus> corpora = Aggregator.getInstance().getCorpora().getCorporaByIds(new HashSet<String>(corporaIds));
112                if (corpora == null || corpora.isEmpty()) {
113                        return Response.status(503).entity("No corpora, please wait for the server to finish scanning").build();
114                }
115
116                if (firstResultIndex == null || firstResultIndex < 1) {
117                        firstResultIndex = 1;
118                }
119                if (firstResultIndex > 250) {
120                        firstResultIndex = 250;
121                }
122
123                if (numberOfResults == null || numberOfResults < 10) {
124                        numberOfResults = 10;
125                }
126                if (numberOfResults > 250) {
127                        numberOfResults = 250;
128                }
129
130                Search search = Aggregator.getInstance().startSearch(SRUVersion.VERSION_1_2,
131                                corpora, query, language, firstResultIndex, numberOfResults);
132                if (search == null) {
133                        return Response.status(500).entity("Initiating search failed").build();
134                }
135                URI uri = URI.create("" + search.getId());
136                return Response.created(uri).entity(uri).build();
137        }
138
139        public static class JsonSearch {
140
141                @JsonProperty
142                int inProgress = 0;
143                @JsonProperty
144                List<Result> results;
145
146                public JsonSearch(List<Result> results) {
147                        this.results = results;
148                }
149        }
150
151        @GET
152        @Path("search/{id}")
153        public Response getSearch(@PathParam("id") Long searchId,
154                        @QueryParam("corpusId") String corpusId) throws Exception {
155                Search search = Aggregator.getInstance().getSearchById(searchId);
156                if (search == null) {
157                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
158                }
159
160                JsonSearch js = new JsonSearch(search.getResults(corpusId));
161                for (Result r : js.results) {
162                        if (r.getInProgress()) {
163                                js.inProgress++;
164                        }
165                }
166                return Response.ok(js).build();
167        }
168
169        @POST
170        @Path("search/{id}")
171        public Response postSearchNextResults(@PathParam("id") Long searchId,
172                        @FormParam("corpusId") String corpusId,
173                        @FormParam("numberOfResults") Integer numberOfResults) throws Exception {
174                log.info("POST /search/{id}, corpusId: " + corpusId);
175                if (corpusId == null || corpusId.isEmpty()) {
176                        return Response.status(400).entity("'corpusId' parameter expected").build();
177                }
178                Search search = Aggregator.getInstance().getSearchById(searchId);
179                if (search == null) {
180                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
181                }
182                if (numberOfResults == null || numberOfResults < 10) {
183                        numberOfResults = 10;
184                }
185                if (numberOfResults > 250) {
186                        numberOfResults = 250;
187                }
188
189                boolean ret = search.searchForNextResults(corpusId, numberOfResults);
190                if (ret == false) {
191                        return Response.status(500).entity("Initiating subSearch failed").build();
192                }
193                URI uri = URI.create("" + search.getId());
194                return Response.created(uri).entity(uri).build();
195        }
196
197        @GET
198        @Path("search/{id}/download")
199        public Response downloadSearchResults(@PathParam("id") Long searchId,
200                        @QueryParam("corpusId") String corpusId,
201                        @QueryParam("filterLanguage") String filterLanguage,
202                        @QueryParam("format") String format) throws Exception {
203                Search search = Aggregator.getInstance().getSearchById(searchId);
204                if (search == null) {
205                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
206                }
207                if (filterLanguage == null || filterLanguage.isEmpty()) {
208                        filterLanguage = null;
209                }
210
211                if (format == null || format.trim().isEmpty() || format.trim().equals("text")) {
212                        String text = Exports.getExportText(search.getResults(corpusId), filterLanguage);
213                        return download(text, MediaType.TEXT_PLAIN, search.getQuery() + ".txt");
214                } else if (format.equals("tcf")) {
215                        byte[] bytes = Exports.getExportTCF(
216                                        search.getResults(corpusId), search.getSearchLanguage(), filterLanguage);
217                        return download(bytes, TCF_MEDIA_TYPE, search.getQuery() + ".xml");
218                } else if (format.equals("excel")) {
219                        byte[] bytes = Exports.getExportExcel(search.getResults(corpusId), filterLanguage);
220                        return download(bytes, EXCEL_MEDIA_TYPE, search.getQuery() + ".xls");
221                } else if (format.equals("csv")) {
222                        String csv = Exports.getExportCSV(search.getResults(corpusId), filterLanguage, ";");
223                        return download(csv, MediaType.TEXT_PLAIN, search.getQuery() + ".csv");
224                }
225
226                return Response.status(Response.Status.BAD_REQUEST)
227                                .entity("format parameter must be one of: text, tcf, excel, csv")
228                                .build();
229        }
230
231        Response download(Object entity, String mediaType, String filesuffix) {
232                if (entity == null) {
233                        return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
234                                        .entity("error while converting to the export format").build();
235                }
236                String filename = EXPORT_FILENAME_PREFIX + filesuffix;
237                return Response.ok(entity, mediaType)
238                                .header("Content-Disposition", "attachment; filename=\"" + filename + "\"")
239                                .build();
240        }
241
242        @GET
243        @Path("search/{id}/toWeblicht")
244        public Response sendSearchResultsToWeblicht(@PathParam("id") Long searchId,
245                        @QueryParam("filterLanguage") String filterLanguage,
246                        @QueryParam("corpusId") String corpusId) throws Exception {
247                Search search = Aggregator.getInstance().getSearchById(searchId);
248                if (search == null) {
249                        return Response.status(Response.Status.NOT_FOUND).entity("Search job not found").build();
250                }
251                if (filterLanguage == null || filterLanguage.isEmpty()) {
252                        filterLanguage = null;
253                }
254
255                String url = null;
256                byte[] bytes = Exports.getExportTCF(
257                                search.getResults(corpusId), search.getSearchLanguage(), filterLanguage);
258                if (bytes != null) {
259                        url = DataTransfer.uploadToDropOff(bytes, "text/tcf+xml", ".tcf");
260                }
261
262                WeblichtConfig weblicht = Aggregator.getInstance().getParams().getWeblichtConfig();
263                URI weblichtUri = new URI(weblicht.getUrl() + url);
264                return url == null
265                                ? Response.status(503).entity("error while exporting to weblicht").build()
266                                : Response.seeOther(weblichtUri).entity(weblichtUri).build();
267        }
268
269        @GET
270        @Path("statistics")
271        public Response getStatistics() throws IOException {
272                final Statistics scan = Aggregator.getInstance().getScanStatistics();
273                final Statistics search = Aggregator.getInstance().getSearchStatistics();
274                final AggregatorConfiguration.Params params = Aggregator.getInstance().getParams();
275
276                Object j = new HashMap<String, Object>() {
277                        {
278                                put("Last Scan", new HashMap<String, Object>() {
279                                        {
280                                                put("maxConcurrentScanRequestsPerEndpoint",
281                                                                Aggregator.getInstance().getParams().getSCAN_MAX_CONCURRENT_REQUESTS_PER_ENDPOINT());
282                                                put("timeout", params.getENDPOINTS_SCAN_TIMEOUT_MS() / 1000.);
283                                                put("isScan", true);
284                                                put("institutions", scan.getInstitutions());
285                                                put("date", scan.getDate());
286                                        }
287                                });
288                                put("Recent Searches", new HashMap<String, Object>() {
289                                        {
290                                                put("maxConcurrentSearchRequestsPerEndpoint",
291                                                                Aggregator.getInstance().getParams().getSEARCH_MAX_CONCURRENT_REQUESTS_PER_ENDPOINT());
292                                                put("timeout", params.getENDPOINTS_SEARCH_TIMEOUT_MS() / 1000.);
293                                                put("isScan", false);
294                                                put("institutions", search.getInstitutions());
295                                                put("date", scan.getDate());
296                                        }
297                                });
298                        }
299                };
300                return Response.ok(toJson(j)).build();
301        }
302
303}
Note: See TracBrowser for help on using the repository browser.