Project

General

Profile

1
package eu.dnetlib.data.search.web.api;
2

    
3
import com.google.common.collect.Iterables;
4
import eu.dnetlib.data.search.app.SearchServiceImpl;
5
import eu.dnetlib.data.search.utils.cql.ParameterQueryEnhancer;
6
import eu.dnetlib.data.search.utils.vocabulary.VocabularyManager;
7
import eu.dnetlib.domain.data.FormattedSearchResult;
8
import org.apache.commons.collections.ListUtils;
9
import org.apache.commons.io.IOUtils;
10
import org.apache.commons.lang.IncompleteArgumentException;
11
import org.apache.commons.lang.StringEscapeUtils;
12
import org.apache.log4j.Logger;
13
import org.springframework.beans.factory.annotation.Autowired;
14
import org.springframework.stereotype.Controller;
15
import org.springframework.ui.ModelMap;
16
import org.springframework.web.bind.annotation.RequestMapping;
17
import org.springframework.web.bind.annotation.RequestMethod;
18

    
19
import javax.annotation.Resource;
20
import javax.servlet.http.HttpServletRequest;
21
import javax.servlet.http.HttpServletResponse;
22
import java.io.PrintWriter;
23
import java.text.SimpleDateFormat;
24
import java.util.*;
25

    
26
@Controller
27
public class SearchRequestController {
28

    
29
	@Autowired
30
	private SearchServiceImpl searchService = null;
31
	@Autowired
32
	private VocabularyManager vocabularyManager = null;
33

    
34
	@Resource
35
	private String maxResults = null;
36

    
37
	@Resource
38
	private String maxSize = null;
39

    
40
	private static Logger logger = Logger.getLogger(SearchRequestController.class);
41

    
42
	private static final String XML_CONTENT_TYPE = "application/xml;charset=UTF-8";
43
	private static final String JSON_CONTENT_TYPE = "application/json;charset=UTF-8;";
44
    private static final String CSV_CONTENT_TYPE = "text/csv;charset=UTF-8;";
45
    private static final String TSV_CONTENT_TYPE = "text/tab-separated-values;charset=UTF-8;";
46
    private static final String HTML_CONTENT_TYPE = "text/html;charset=UTF-8;";
47

    
48
    private static final String PUBLICATION_BASIC_QUERY = "(oaftype exact result) and (resulttypeid exact publication)";
49
    private static final String DATASET_BASIC_QUERY = "(oaftype exact result) and (resulttypeid exact dataset)";
50
    private static final String PROJECT_BASIC_QUERY = "(oaftype exact project)";
51

    
52
    private static final List<String> GLOBAL_PARAMETERS = Arrays.asList("page", "size", "format", "sortBy");
53

    
54
    private static final List<String> PUB_N_DATA_COMMON_PARAMETERS = Arrays.asList("author", "doi", "FP7ProjectID", "FP7scientificArea",
55
            "fromDateAccepted", "funder", "fundingStream", "hasECFunding", "hasProject", "hasWTFunding", "keywords",
56
            "model", "OA", "openaireAuthorID", "openaireProjectID", "openaireProviderID", "projectID", "title", "toDateAccepted");
57

    
58
    private static final List<String> PUB_PARAMETERS = Arrays.asList("openairePublicationID");
59
    private static final List<String> DATA_PARAMETERS = Arrays.asList("openaireDatasetID");
60

    
61
    private static final List<String> PUB_N_DATASET_MODELS = Arrays.asList("dc", "openaire", "sygma");
62
    private static final List<String> PUB_N_DATASET_FORMATS = Arrays.asList("json", "rss", "xml", "csv", "tsv", "html");
63

    
64
    private static final List<String> PROJECT_PARAMETERS = Arrays.asList("acronym", "callID", "endYear", "FP7scientificArea",
65
            "funder", "fundingStream", "grantID", "hasECFunding", "hasWTFunding", "keywords", "name",
66
            "participantAcronyms", "participantCountries", "startYear", "sc39", "openaireParticipantID", "openaireProjectID");
67
    private static final List<String> PROJECT_FORMATS = Arrays.asList("xml", "json", "csv", "tsv", "html");
68

    
69
	@RequestMapping(value = "/search", method = RequestMethod.GET)
70
	public void search(HttpServletRequest request, HttpServletResponse response) {
71
		PrintWriter writer = null;
72
		FormattedSearchResult formattedSearchResult = null;
73

    
74
        String action = readActionParameter(request);
75
        String query = readQueryParameter(request);
76
		String format = (request.getParameter("format") != null) ? request.getParameter("format") : "xml";
77
        createResponseMeta(response, format);
78

    
79
		String locale = request.getParameter("locale");
80

    
81
        int page= 0;
82
        int size =-1;
83
        //TODO check paging
84
        if (!action.equals("refine")) {
85
            page = readParameter(request, "page", 1);
86
            size = readParameter(request, "size", 10);
87
        }
88
        
89
		if (size > Integer.parseInt(maxSize)) {
90
			throw new IllegalArgumentException("Size argument have exceeded the maximum allowed number.");
91
		}
92

    
93
		String sTransformer = request.getParameter("sTransformer");
94
		String rTransformer = request.getParameter("rTransformer");
95
		Collection<String> fields = readParameter(request, "fields");
96

    
97
        checkTransformerParameters(action, sTransformer, rTransformer, fields);
98

    
99
        try {
100
            createResponseMeta(response, format);
101
            writer = response.getWriter();
102

    
103
            formattedSearchResult = searchService.searchNrefine(query,
104
                    sTransformer, rTransformer, format, locale, page, size,
105
                    fields);
106

    
107
			writer.append(formattedSearchResult.getFormattedResult());
108

    
109
		} catch (Exception e) {
110
			logger.error("Fail to execute search.", e);
111
			createXmlErrorPage(writer, e);
112

    
113
		} finally {
114
            if (writer != null) {
115
                writer.close();
116
            }
117
		}
118
	}
119

    
120
    private void checkTransformerParameters(String action, String sTransformer, String rTransformer, Collection<String> fields) {
121
        if (action.equals("search")) {
122
            if (sTransformer == null) {
123
                throw new IncompleteArgumentException("Undefined search transformer. Search request");
124
            }
125

    
126
        } else if (action.equals("refine")) {
127
            if (rTransformer == null) {
128
                throw new IncompleteArgumentException(
129
                        "Undefined refine transformer. Refine request");
130
            }
131

    
132
            if (fields == null) {
133
                throw new IncompleteArgumentException(
134
                        "Undefined refine fields. Refine request");
135
            }
136

    
137
        } else if (action.equals("searchNrefine")) {
138

    
139
            if (sTransformer == null) {
140
                throw new IncompleteArgumentException(
141
                        "Undefined search transformer. Search and Refine request");
142
            }
143

    
144
            if (rTransformer == null) {
145
                throw new IncompleteArgumentException(
146
                        "Undefined refine transformer. Search and Refine request");
147
            }
148

    
149
            if (fields == null) {
150
                throw new IncompleteArgumentException(
151
                        "Undefined refine fields. Search and Refine request");
152
            }
153

    
154
        } else {
155
            throw new UnsupportedOperationException("The action " + action
156
                    + " is not supported. Please try one of {search, refine, searchNrefine}.");
157
        }
158
    }
159

    
160
    private String readQueryParameter(HttpServletRequest request) {
161
        String query = request.getParameter("query");
162
        if (query == null) {
163
            throw new IncompleteArgumentException("Undefined query. Search request");
164
        }
165
        return query;
166
    }
167

    
168
    private String readActionParameter(HttpServletRequest request) {
169
        String action = request.getParameter("action");
170
        if (action == null) {
171
            throw new UnsupportedOperationException("Undefined action.");
172
        }
173
        return action;
174
    }
175

    
176

    
177
    @RequestMapping(value="/search/openSearchDescriptor", method = RequestMethod.GET)
178
    public String printOpenSearchDescriptor(ModelMap model) {
179
        return "openSearchDescriptor";
180
    }
181

    
182
	@RequestMapping(value = "/api/publications", method = RequestMethod.GET)
183
	public void searchPublications(HttpServletRequest request, HttpServletResponse response) {
184

    
185
		PrintWriter writer = null;
186

    
187
        try {
188
            writer = response.getWriter();
189

    
190
            checkParameters(ListUtils.union(PUB_N_DATA_COMMON_PARAMETERS, PUB_PARAMETERS),request.getParameterMap());
191

    
192
            int page = readParameter(request, "page", 1);
193
            int size = readParameter(request, "size", 10);
194
            checkRequestSize(page, size);
195

    
196
            String format = (request.getParameter("format") != null) ? request.getParameter("format") : "xml";
197
            checkFormatParameter(PUB_N_DATASET_FORMATS, format);
198
            createResponseMeta(response, format);
199

    
200
            String locale = request.getParameter("locale");
201

    
202
            String model = request.getParameter("model");
203
            checkModelParameter(PUB_N_DATASET_MODELS, model);
204
            String sTransformer = defineTransformer(model,format);
205

    
206
            Collection<String> referrers = readParameter(request,"referrer");
207
            String newFormat = defineFormatter(model, format, true, referrers);
208

    
209
            StringBuilder queryBuilder = new StringBuilder();
210
            queryBuilder.append(PUBLICATION_BASIC_QUERY);
211

    
212
			ParameterQueryEnhancer.enhanceQueryWithFundingLevelParams(queryBuilder, request, vocabularyManager, isModelSygma(model));
213
            ParameterQueryEnhancer.enhanceQueryWithOpenAIREIds(queryBuilder, request);
214
            ParameterQueryEnhancer.enhanceQueryWithMetadataKeywords(queryBuilder, request);
215
            ParameterQueryEnhancer.enhanceQueryWithFundingParams(queryBuilder, request);
216
            ParameterQueryEnhancer.enhanceQueryWithRelProjectParams(queryBuilder, request);
217
            ParameterQueryEnhancer.enhanceQueryWithAccessRights(queryBuilder, request);
218
            ParameterQueryEnhancer.enhanceQueryWithDate(queryBuilder, request);
219
            ParameterQueryEnhancer.enhanceQueryWithDoi(queryBuilder, request);
220

    
221
            ParameterQueryEnhancer.enhanceQueryWithResultsSortParameters(queryBuilder, request);
222

    
223
			FormattedSearchResult formattedSearchResult = searchService.search(queryBuilder.toString(),sTransformer, (newFormat!=null)?newFormat:format, locale, page, size);
224
			writer.append(formattedSearchResult.getFormattedResult());
225

    
226
		} catch (Exception e) {
227
			logger.error("Fail to execute search.", e);
228
			createXmlErrorPage(writer, e);
229

    
230
		} finally {
231
            if (writer != null) {
232
                IOUtils.closeQuietly(writer);
233
            }
234
		}
235
	}
236

    
237
	@RequestMapping(value = "/api/datasets", method = RequestMethod.GET)
238
	public void searchData(HttpServletRequest request, HttpServletResponse response) {
239

    
240
		PrintWriter writer = null;
241

    
242
        try {
243
            writer = response.getWriter();
244

    
245
            checkParameters(ListUtils.union(PUB_N_DATA_COMMON_PARAMETERS, DATA_PARAMETERS),request.getParameterMap());
246

    
247
            int page = readParameter(request, "page", 1);
248
            int size = readParameter(request, "size", 10);
249
            checkRequestSize(page, size);
250

    
251
            String format = (request.getParameter("format") != null) ? request.getParameter("format") : "xml";
252
            createResponseMeta(response, format);
253

    
254
            checkFormatParameter(PUB_N_DATASET_FORMATS, format);
255

    
256
            String model = request.getParameter("model");
257
            checkModelParameter(PUB_N_DATASET_MODELS, model);
258
            String sTransformer = defineTransformer(model,format);
259

    
260
            Collection<String> referrers = readParameter(request,"referrer");
261
            String newFormat = defineFormatter(model, format, false, referrers);
262

    
263
            String locale = request.getParameter("locale");
264

    
265
            StringBuilder queryBuilder = new StringBuilder();
266
            queryBuilder.append(DATASET_BASIC_QUERY);
267

    
268
            ParameterQueryEnhancer.enhanceQueryWithFundingLevelParams(queryBuilder, request, vocabularyManager, isModelSygma(model));
269
            ParameterQueryEnhancer.enhanceQueryWithOpenAIREIds(queryBuilder, request);
270
            ParameterQueryEnhancer.enhanceQueryWithMetadataKeywords(queryBuilder, request);
271
            ParameterQueryEnhancer.enhanceQueryWithFundingParams(queryBuilder, request);
272
            ParameterQueryEnhancer.enhanceQueryWithRelProjectParams(queryBuilder, request);
273
            ParameterQueryEnhancer.enhanceQueryWithAccessRights(queryBuilder, request);
274
            ParameterQueryEnhancer.enhanceQueryWithDate(queryBuilder, request);
275
            ParameterQueryEnhancer.enhanceQueryWithDoi(queryBuilder, request);
276

    
277
            ParameterQueryEnhancer.enhanceQueryWithResultsSortParameters(queryBuilder, request);
278

    
279
			FormattedSearchResult formattedSearchResult =  searchService.search(queryBuilder.toString(),sTransformer, (newFormat!=null)?newFormat:format, locale, page, size);
280
			writer.append(formattedSearchResult.getFormattedResult());
281

    
282
		} catch (Exception e) {
283
			logger.error("Fail to execute search.", e);
284
			createXmlErrorPage(writer, e);
285

    
286
		} finally {
287
            if (writer != null) {
288
                IOUtils.closeQuietly(writer);
289
            }
290
		}
291

    
292
	}
293

    
294
	@RequestMapping(value = "/api/projects", method = RequestMethod.GET)
295
	public void searchProjects(HttpServletRequest request, HttpServletResponse response)  {
296

    
297
		PrintWriter writer = null;
298

    
299
        try {
300
            writer = response.getWriter();
301

    
302
            checkParameters(PROJECT_PARAMETERS, request.getParameterMap());
303

    
304
            int page = readParameter(request, "page", 1);
305
            int size = readParameter(request, "size", 10);
306
            checkRequestSize(page, size);
307

    
308
            StringBuilder queryBuilder = new StringBuilder();
309
            queryBuilder.append(PROJECT_BASIC_QUERY);
310
            String locale = request.getParameter("locale");
311

    
312
            String format = (request.getParameter("format") != null) ? request.getParameter("format") : "xml";
313
            checkFormatParameter(PROJECT_FORMATS, format);
314
            createResponseMeta(response, format);
315

    
316
            format = finalFormat(format);
317

    
318

    
319
            String sTransformer = request.getParameter("sTransformer");
320

    
321
            FormattedSearchResult formattedSearchResult = null;
322

    
323
            ParameterQueryEnhancer.enhanceProjectQueryWithOpenAIREIds(queryBuilder, request);
324
            ParameterQueryEnhancer.enhanceQueryWithProjectMetadataKeywords(queryBuilder, request);
325
            ParameterQueryEnhancer.enhanceQueryWithProjectFundingParams(queryBuilder, request);
326
            ParameterQueryEnhancer.enhanceProjectQueryWithFundingLevelParams(queryBuilder, request, vocabularyManager);
327
            ParameterQueryEnhancer.enhanceQueryWithParticipantsInfoParams(queryBuilder, request);
328
            ParameterQueryEnhancer.enhanceQueryWithYearParams(queryBuilder, request);
329
            ParameterQueryEnhancer.enhanceQueryWithSC39Params(queryBuilder, request);
330

    
331
            ParameterQueryEnhancer.enhanceQueryWithProjectSortParameters(queryBuilder, request);
332

    
333
			formattedSearchResult = searchService.search(queryBuilder.toString(),sTransformer, format, locale, page, size);
334
			writer.append(formattedSearchResult.getFormattedResult());
335

    
336
		} catch (Exception e) {
337
			logger.error("Fail to execute search.", e);
338
            createXmlErrorPage(writer, e);
339

    
340
		} finally {
341
            if (writer != null) {
342
                IOUtils.closeQuietly(writer);
343
            }
344
		}
345
	}
346

    
347
    private String finalFormat(String format) {
348
        if (format.equals("tsv")){
349
            return "project_tsv";
350

    
351
        } else if (format.equals("csv")) {
352
            return "project_csv";
353

    
354
        } else if (format.equals("html")) {
355
            return "project_html";
356
        }
357

    
358
        return format;
359
    }
360

    
361
    private String finalFormat(String format, String referrer) {
362
        if (referrer == null || referrer.isEmpty() || !referrer.equals("joomla")) {
363
            return finalFormat(format);
364
        }
365

    
366
        if (format.equals("tsv")){
367
            return "publication_tsv_notitle";
368

    
369
        } else if (format.equals("csv")) {
370
            return "publication_csv_notitle";
371

    
372
        }
373

    
374
        return format;
375
    }
376

    
377
    /** TODO: check if needed
378
     * Based on the given model the transformer to be used is defined
379
     * @param model
380
     * @return
381

    
382
    private String defineTransformer(String model) {
383
        if (model!=null && !model.trim().isEmpty()) {
384
            if (model.equals("openaire")) {
385
                return null;
386

    
387
            } else if (model.equals("sygma")) {
388
                return "results_openaire";
389
            }
390
            else if (model.equals("dc")) {
391
                return "dc";
392
            }
393

    
394
            throw new IllegalArgumentException("model '" + model + "' is not supported.");
395

    
396
        } else {
397
            return null;
398
        }
399
    }*/
400

    
401
    //TODO: check if needed
402
 private String defineTransformer(String model, String format) {
403
   if (model!=null && !model.trim().isEmpty()) {
404
            if (model.equals("openaire")) {
405
                return null;
406

    
407
            } else if (model.equals("sygma")) {
408
                return "results_openaire";
409
            }
410
            else if (model.equals("dc")) {
411
                return "dc";
412
            }
413

    
414
            throw new IllegalArgumentException("model '" + model + "' is not supported.");
415

    
416
        } else if (format!=null && !format.trim().isEmpty()) {
417
            if (format.equals("rss") || format.equals("csv") || format.equals("tsv") || format.equals("html")) {
418
			    return "results_openaire";
419
		    }
420
        } 
421
		return null;
422
	
423
    }
424

    
425
    private String defineFormatter(String model, String format, boolean isPublications, Collection<String> referrers) {
426
        if( model != null && !model.trim().isEmpty() ) {
427
            if (model.equals("sygma")) {
428

    
429
                if (isPublications) {
430
                    return "sygma_publication";
431
                }
432
                return "sygma_dataset";
433
            }
434
        } else {
435
            if (referrers != null && !referrers.isEmpty() && Iterables.get(referrers, 0) != null && !Iterables.get(referrers, 0).isEmpty()) {
436
                return finalFormat(format, Iterables.get(referrers, 0));
437
            } else {
438
                format = finalFormat(format);
439
            }
440
        }
441

    
442
        return null;
443
    }
444

    
445
    private void createXmlErrorPage(PrintWriter writer, Exception e) {
446
		writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
447
		writer.append("<error>");
448
		writer.append("<exception>")
449
				.append(StringEscapeUtils.escapeXml(e.getClass().getName()))
450
				.append("</exception>");
451
		if (e.getMessage() != null) {
452
			writer.append("<message>")
453
					.append(StringEscapeUtils.escapeXml(e.getMessage()))
454
					.append("</message>");
455
		}
456
		if (e.getCause() != null) {
457
			writer.append("<cause>")
458
					.append(StringEscapeUtils.escapeXml(e.getCause()
459
							.toString())).append("</cause>");
460
		}
461

    
462
		StackTraceElement[] trace = e.getStackTrace();
463
		writer.append("<trace>");
464
		for (int i = 0; i < trace.length; i++) {
465
			writer.append(StringEscapeUtils.escapeXml(trace[i].toString()))
466
					.append("\n");
467
		}
468
		writer.append("</trace>");
469

    
470
		writer.append("</error>");
471
	}
472

    
473
    // Reading parameters from url and adding default values
474
    public int readParameter(HttpServletRequest request, String parameterName, int defaultValue) {
475
        String param = request.getParameter(parameterName);
476
        return (param != null && !param.isEmpty()) ? Integer.parseInt(param) : defaultValue;
477
    }
478

    
479
    private Collection<String> readParameter(HttpServletRequest request, String parameterName) {
480
        Collection<String> fields = null;
481
        String[] paramfields = request.getParameterValues(parameterName);
482
        if (paramfields != null) {
483
            fields = new ArrayList<String>();
484
            for (int i = 0; i < paramfields.length; i++) {
485
                fields.add(paramfields[i]);
486
            }
487
        }
488
        return fields;
489
    }
490

    
491
    /**
492
	 * Checks if the requested result size exceeds the maximum allowed numbers of returned results
493
	 * @param page the page parameter
494
	 * @param size the size parameter
495
	 */
496
	private void checkRequestSize(int page, int size) {
497
		int total = page*size;
498
		if (total > Integer.parseInt(maxResults)) {
499
			throw new IllegalArgumentException("Size and page arguments have exceeded the maximum number of returned results.");
500
		}
501
	}
502

    
503
    private String defineContentType(String format) {
504
        if (format != null) {
505
            if (format.equalsIgnoreCase("xml")) {
506
                return XML_CONTENT_TYPE;
507
            } else if (format.equalsIgnoreCase("json")) {
508
                return JSON_CONTENT_TYPE;
509

    
510
			} else if (format.equalsIgnoreCase("csv")) {
511
                return CSV_CONTENT_TYPE;
512

    
513
            } else if (format.equalsIgnoreCase("tsv")) {
514
                return TSV_CONTENT_TYPE;
515

    
516
            } else if (format.equalsIgnoreCase("html")){
517
                return HTML_CONTENT_TYPE;
518
            }
519
        }
520

    
521
        return XML_CONTENT_TYPE;
522
    }
523
    /**
524
     * Checks if the parameters given are allowed. The given parameters are checked against the allowed parameter
525
     * and the GLOBAL_PARAMETERS.
526
     * @param allowedParameters the allowed parameters
527
     * @param currentParameters the given parameters
528
     */
529
    private void checkParameters(List<String> allowedParameters, Map<String, String[]> currentParameters){
530
        if(currentParameters != null) {
531
            for (String parameter : currentParameters.keySet()) {
532
                if (!allowedParameters.contains(parameter) && !GLOBAL_PARAMETERS.contains(parameter) && !parameter.equals("referrer")) {
533
                    throw new IllegalArgumentException("Parameter " + parameter + " is not supported. The supported parameters are: " +
534
                            allowedParameters.toString().replace("[","").replace("]", ", ") + GLOBAL_PARAMETERS.toString().substring(1,GLOBAL_PARAMETERS.toString().length()-1));
535
                }
536
            }
537
        }
538
    }
539

    
540
    private void checkFormatParameter(List<String> allowedFormats, String requestedFormat) {
541
        if (requestedFormat!= null && !allowedFormats.contains(requestedFormat)) {
542
            throw new IllegalArgumentException("The requested format \'"+ requestedFormat +"\' is not supported. The supported formats are: " + allowedFormats);
543
        }
544
    }
545

    
546
    private static void checkModelParameter(List<String> allowedModels, String requestedModel) {
547
        if (requestedModel!= null && !allowedModels.contains(requestedModel)) {
548
            throw new IllegalArgumentException("The requested model \'"+ allowedModels +"\' is not supported. The supported formats are: " + allowedModels);
549
        }
550
    }
551

    
552
    private static boolean isModelSygma(String model) {
553
        if (model == null || model.isEmpty()) { return false; }
554

    
555
        if (!model.isEmpty() && !model.equals("sygma")) {
556
            return  false;
557
        }
558

    
559
        return true;
560
    }
561

    
562
    private void createResponseMeta( HttpServletResponse response, String format) {
563
        response.setContentType(defineContentType(format));
564
        response.setCharacterEncoding("UTF-8");
565

    
566
        if (!format.equals("xml") || !format.equals("json")) {
567

    
568
            SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
569
            String date = sdf.format(new Date());
570

    
571
            if (format.equals("csv")) {
572
                response.setHeader("Content-Disposition", "filename="+date+".csv");
573

    
574
            } else if (format.equals("csv")) {
575
                response.setHeader("Content-Disposition", "filename="+date+".tsv");
576

    
577
            } else if (format.equals("html")) {
578
                response.setHeader("Content-Disposition", "filename="+date+".html");
579
            }
580
        }
581
    }
582
}
(6-6/8)