Project

General

Profile

1
package eu.dnetlib.repo.manager.service;
2

    
3
import com.fasterxml.jackson.databind.ObjectMapper;
4
import com.google.gson.JsonArray;
5
import com.google.gson.JsonElement;
6
import com.google.gson.JsonObject;
7
import eu.dnetlib.api.functionality.ValidatorServiceException;
8
import eu.dnetlib.domain.data.Repository;
9
import eu.dnetlib.domain.data.RepositoryInterface;
10
import eu.dnetlib.domain.enabling.Vocabulary;
11
import eu.dnetlib.domain.functionality.validator.JobForValidation;
12
import eu.dnetlib.repo.manager.domain.*;
13
import eu.dnetlib.repo.manager.domain.dto.Role;
14
import eu.dnetlib.repo.manager.exception.ResourceNotFoundException;
15
import eu.dnetlib.repo.manager.service.aai.registry.AaiRegistryService;
16
import eu.dnetlib.repo.manager.service.security.RoleMappingService;
17
import eu.dnetlib.repo.manager.service.security.AuthoritiesUpdater;
18
import eu.dnetlib.repo.manager.utils.Converter;
19
import gr.uoa.di.driver.enabling.vocabulary.VocabularyLoader;
20
import org.apache.commons.codec.digest.DigestUtils;
21
import org.apache.log4j.Logger;
22
import org.json.JSONArray;
23
import org.json.JSONException;
24
import org.json.JSONObject;
25
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
26
import org.springframework.beans.factory.annotation.Autowired;
27
import org.springframework.beans.factory.annotation.Value;
28
import org.springframework.context.annotation.Lazy;
29
import org.springframework.core.ParameterizedTypeReference;
30
import org.springframework.http.*;
31
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
32
import org.springframework.security.core.Authentication;
33
import org.springframework.security.core.context.SecurityContextHolder;
34
import org.springframework.stereotype.Service;
35
import org.springframework.web.client.HttpClientErrorException;
36
import org.springframework.web.client.RestClientException;
37
import org.springframework.web.client.RestTemplate;
38
import org.springframework.web.util.UriComponents;
39
import org.springframework.web.util.UriComponentsBuilder;
40

    
41
import javax.annotation.PostConstruct;
42
import java.io.IOException;
43
import java.sql.Timestamp;
44
import java.util.*;
45
import java.util.concurrent.ConcurrentHashMap;
46
import java.util.stream.Collectors;
47

    
48
@Service("repositoryService")
49
public class RepositoryServiceImpl implements RepositoryService {
50

    
51
    private static final Logger LOGGER = Logger.getLogger(RepositoryServiceImpl.class);
52

    
53
    private final RoleMappingService roleMappingService;
54
    private final AaiRegistryService registryCalls;
55
    private final AuthoritiesUpdater authoritiesUpdater;
56
    private final RestTemplate restTemplate;
57
    private final VocabularyLoader vocabularyLoader;
58
    private final PiWikService piWikService;
59
    private final EmailUtils emailUtils;
60
    private final ValidatorService validatorService;
61

    
62
    @Value("${api.baseAddress}")
63
    private String baseAddress;
64

    
65
    @Value("${services.repo-manager.adminEmail}")
66
    private String adminEmail;
67

    
68
    @Value("${services.repomanager.usageStatisticsDiagramsBaseURL}")
69
    private String usageStatisticsDiagramsBaseURL;
70

    
71
    @Value("${services.repomanager.usageStatisticsNumbersBaseURL}")
72
    private String usageStatisticsNumbersBaseURL;
73

    
74

    
75
    private static final Map<String, List<String>> dataSourceClass = new HashMap<>();
76
    private static final Map<String, String> invertedDataSourceClass = new HashMap<>();
77

    
78

    
79
    private final String[] vocabularyNames = {"dnet:countries", "dnet:datasource_typologies", "dnet:compatibilityLevel"};
80
    private final Map<String, Vocabulary> vocabularyMap = new ConcurrentHashMap<>();
81
    private final Map<String, String> countriesMap = new HashMap<>();
82
    private final Map<String, String> inverseCountriesMap = new HashMap<>();
83

    
84
    private HttpHeaders httpHeaders;
85

    
86
    @Autowired
87
    public RepositoryServiceImpl(RoleMappingService roleMappingService,
88
                                 AaiRegistryService registryCalls,
89
                                 AuthoritiesUpdater authoritiesUpdater,
90
                                 VocabularyLoader vocabularyLoader,
91
                                 RestTemplate restTemplate,
92
                                 @Lazy EmailUtils emailUtils,
93
                                 @Lazy ValidatorService validatorService,
94
                                 @Lazy PiWikService piWikService) {
95
        this.roleMappingService = roleMappingService;
96
        this.registryCalls = registryCalls;
97
        this.authoritiesUpdater = authoritiesUpdater;
98
        this.vocabularyLoader = vocabularyLoader;
99
        this.piWikService = piWikService;
100
        this.emailUtils = emailUtils;
101
        this.validatorService = validatorService;
102
        this.restTemplate = restTemplate;
103
    }
104

    
105
    private String sendEmail() {
106
        OIDCAuthenticationToken authenticationToken = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
107
        return authenticationToken.getUserInfo().getEmail();
108
    }
109

    
110

    
111
    @PostConstruct
112
    private void init() {
113
        LOGGER.debug("Initialization method of repository api!");
114
        LOGGER.debug("Updated version!");
115

    
116
        dataSourceClass.put("opendoar", Arrays.asList("pubsrepository::institutional", "pubsrepository::thematic", "pubsrepository::unknown", "pubsrepository::mock"));
117
        dataSourceClass.put("re3data", Collections.singletonList("datarepository::unknown"));
118
        dataSourceClass.put("journal", Collections.singletonList("pubsrepository::journal"));
119
        dataSourceClass.put("aggregator", Arrays.asList("aggregator::pubsrepository::institutional", "aggregator::pubsrepository::journals", "aggregator::datarepository", "aggregator::pubsrepository::unknown"));
120

    
121
        invertedDataSourceClass.put("pubsrepository::institutional", "opendoar");
122
        invertedDataSourceClass.put("pubsrepository::thematic", "opendoar");
123
        invertedDataSourceClass.put("pubsrepository::unknown", "opendoar");
124
        invertedDataSourceClass.put("pubsrepository::mock", "opendoar");
125
        invertedDataSourceClass.put("datarepository::unknown", "re3data");
126
        invertedDataSourceClass.put("pubsrepository::journal", "journal");
127
        invertedDataSourceClass.put("aggregator::pubsrepository::institutional", "aggregator");
128
        invertedDataSourceClass.put("aggregator::pubsrepository::journals", "aggregator");
129
        invertedDataSourceClass.put("aggregator::datarepository", "aggregator");
130
        invertedDataSourceClass.put("aggregator::pubsrepository::unknown", "aggregator");
131

    
132

    
133
        httpHeaders = new HttpHeaders();
134
        httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
135

    
136
        for (String vocName : vocabularyNames) {
137
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
138
        }
139

    
140
        Country[] countries = getCountries();
141
        for (Country c : countries) {
142
            countriesMap.put(c.getName(), c.getCode());
143
            inverseCountriesMap.put(c.getCode(), c.getName());
144
        }
145

    
146

    
147
    }
148

    
149
    @Override
150
    public Country[] getCountries() {
151
        UriComponents uriComponents = UriComponentsBuilder
152
                .fromHttpUrl(baseAddress + "/ds/countries")
153
                .build().encode();
154
        return restTemplate.getForObject(uriComponents.toUri(), Country[].class);
155
    }
156

    
157

    
158
    @Override
159
    public List<RepositorySnippet> getRepositoriesByCountry(String country,
160
                                                            String mode,
161
                                                            Boolean managed) throws JSONException, IOException {
162

    
163
        LOGGER.debug("Getting repositories by country!");
164
        int page = 0;
165
        int size = 100;
166
        List<RepositorySnippet> resultSet = new ArrayList<>();
167
        ObjectMapper mapper = new ObjectMapper();
168

    
169
        String filterKey = "UNKNOWN";
170
        if (mode.equalsIgnoreCase("opendoar"))
171
            filterKey = "openaire____::opendoar";
172
        else if (mode.equalsIgnoreCase("re3data"))
173
            filterKey = "openaire____::re3data";
174

    
175

    
176
        LOGGER.debug("Country code equals : " + country);
177
        LOGGER.debug("Filter mode equals : " + filterKey);
178

    
179
        UriComponents uriComponents = searchSnipperDatasource(String.valueOf(page), String.valueOf(size));
180
        RequestFilter requestFilter = new RequestFilter();
181
        requestFilter.setCountry(country);
182
        requestFilter.setCollectedfrom(filterKey);
183

    
184
        try {
185
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
186
            JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
187
            while (jsonArray.length() > 0) {
188
                resultSet.addAll(mapper.readValue(String.valueOf(jsonArray),
189
                        mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
190
                page += 1;
191
                uriComponents = searchSnipperDatasource(String.valueOf(page), String.valueOf(size));
192
                rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
193
                jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
194
            }
195
            return resultSet;
196
        } catch (Exception e) {
197
            LOGGER.debug("Exception on getRepositoriesByCountry", e);
198
//            emailUtils.reportException(e);
199
            throw e;
200
        }
201
    }
202

    
203
    public List<RepositorySnippet> searchRegisteredRepositories(String country, String typology, String englishName,
204
                                                                String officialName, String requestSortBy, String order, int page, int pageSize) throws Exception {
205

    
206
        LOGGER.debug("Searching registered repositories");
207

    
208
        List<RepositorySnippet> resultSet = new ArrayList<>();
209
        ObjectMapper mapper = new ObjectMapper();
210

    
211
        UriComponents uriComponents = searchRegisteredDatasource(requestSortBy, order, Integer.toString(page), Integer.toString(pageSize));
212

    
213
        RequestFilter requestFilter = new RequestFilter();
214
        requestFilter.setCountry(country);
215
        requestFilter.setTypology(typology);
216
        requestFilter.setOfficialname(officialName);
217
        requestFilter.setEnglishname(englishName);
218

    
219
        try {
220
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
221
            JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
222

    
223
            resultSet.addAll(mapper.readValue(String.valueOf(jsonArray), mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
224

    
225
            return resultSet;
226
        } catch (Exception e) {
227
            LOGGER.error("Error searching registered datasources", e);
228
            throw e;
229
        }
230
    }
231

    
232
    private Repository updateRepositoryInfo(Repository r) throws JSONException {
233

    
234
        /*
235
         * from datasource class
236
         * we get the datasource type form the inverted map
237
         * */
238
        r.setDatasourceType(getRepositoryType(r.getDatasourceClass()));
239
        r.setInterfaces(this.getRepositoryInterface(r.getId()));
240
        r.setPiwikInfo(piWikService.getPiwikSiteForRepo(r.getId()));
241
        r.setCountryName(getCountryName(r.getCountryCode()));
242
        return r;
243
    }
244

    
245

    
246
    private Collection<Repository> getRepositoriesByMode(String mode, List<Repository> rs) {
247

    
248
        List<Repository> reps = new ArrayList<>();
249
        for (Repository r : rs) {
250
            if (r.getCollectedFrom() != null && r.getCollectedFrom().equals(mode))
251
                reps.add(r);
252

    
253
        }
254
        return reps;
255
    }
256

    
257
    @Override
258
    public List<Repository> getRepositoriesOfUser(String userEmail,
259
                                                  String page,
260
                                                  String size) throws JSONException {
261

    
262
        LOGGER.debug("Retreiving repositories of user : " + userEmail);
263
        UriComponents uriComponents = searchDatasource(page, size);
264
        RequestFilter requestFilter = new RequestFilter();
265
//        requestFilter.setRegisteredby(userEmail);
266

    
267
        List<String> repoIds = getRepoIdsFromUserRoles(userEmail);
268
        List<Repository> repos = new ArrayList<>();
269

    
270
        try {
271
            for (String repoId : repoIds) {
272
                requestFilter.setId(repoId);
273
                String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
274

    
275
                repos.addAll(Converter.jsonToRepositoryList(new JSONObject(rs)));
276
            }
277
        } catch (Exception e) {
278
            LOGGER.debug("Exception on getRepositoriesOfUser", e);
279
            emailUtils.reportException(e);
280
            throw e;
281
        }
282

    
283
        for (Repository r : repos)
284
            r.setPiwikInfo(piWikService.getPiwikSiteForRepo(r.getId()));
285
        return repos;
286
    }
287

    
288
    @Override
289
    public List<RepositorySnippet> getRepositoriesSnippetOfUser(String userEmail, String page, String size) throws IOException, JSONException {
290

    
291
        // TODO: Step 3 - For each repo from the previous step call findByRepositoryId piwik_site to get the full info of repo
292
        List<String> repoIds = getRepoIdsFromUserRoles(userEmail);
293

    
294
        List<RepositorySnippet> resultSet = new ArrayList<>();
295
        ObjectMapper mapper = new ObjectMapper();
296

    
297
        // here page should be 0
298
        UriComponents uriComponents = searchSnipperDatasource(page, size);
299
        RequestFilter requestFilter = new RequestFilter();
300

    
301
        try {
302
            for (String repoId : repoIds) {
303
                requestFilter.setId(repoId);
304

    
305
                String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
306
                JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
307
                resultSet.addAll(mapper.readValue(String.valueOf(jsonArray),
308
                        mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
309
            }
310
        } catch (Exception e) {
311
            LOGGER.debug("Exception on getRepositoriesSnippetOfUser", e);
312
            throw e;
313
        }
314

    
315
        LOGGER.debug("resultSet:" + resultSet);
316
        resultSet.parallelStream().forEach(repositorySnippet -> {
317
            repositorySnippet.setPiwikInfo(piWikService.getPiwikSiteForRepo(repositorySnippet.getId()));
318
        });
319
        return resultSet;
320
    }
321

    
322
    @Override
323
    public RepositorySnippet getRepositorySnippetById(String id) throws JSONException, ResourceNotFoundException {
324

    
325
        LOGGER.debug("Retreiving repositories with id : " + id);
326
        RepositorySnippet repo = null;
327
        UriComponents uriComponents = searchSnipperDatasource("0", "100");
328
        RequestFilter requestFilter = new RequestFilter();
329
        requestFilter.setId(id);
330

    
331
        try {
332
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
333
            JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
334

    
335
            if (jsonArray.length() == 0)
336
                throw new ResourceNotFoundException();
337

    
338
            repo = Converter.jsonToRepositorySnippetObject(jsonArray.getJSONObject(0));
339
            return repo;
340
        } catch (JSONException e) {
341
            LOGGER.debug("Exception on getRepositoryById", e);
342
            emailUtils.reportException(e);
343
            throw e;
344
        }
345

    
346
    }
347

    
348
    @Override
349
    public Repository getRepositoryById(String id) throws JSONException, ResourceNotFoundException {
350

    
351
        LOGGER.debug("Retreiving repositories with id : " + id);
352
        Repository repo = null;
353
        UriComponents uriComponents = searchDatasource("0", "100");
354
        RequestFilter requestFilter = new RequestFilter();
355
        requestFilter.setId(id);
356

    
357
        try {
358
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
359
            JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
360

    
361
            if (jsonArray.length() == 0)
362
                throw new ResourceNotFoundException();
363

    
364
            repo = Converter.jsonToRepositoryObject(jsonArray.getJSONObject(0));
365
            return updateRepositoryInfo(repo);
366
        } catch (JSONException e) {
367
            LOGGER.debug("Exception on getRepositoryById", e);
368
            emailUtils.reportException(e);
369
            throw e;
370
        }
371

    
372
    }
373

    
374

    
375
    @Override
376
    public List<AggregationDetails> getRepositoryAggregations(String id, int from, int size) throws JSONException {
377

    
378
        LOGGER.debug("Retreiving aggregations for repository with id : " + id);
379
        UriComponents uriComponents = searchDatasource(from + "", size + "");
380
        RequestFilter requestFilter = new RequestFilter();
381
        requestFilter.setId(id);
382

    
383
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
384

    
385
        try {
386
            long start = System.currentTimeMillis();
387
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
388
            long end = System.currentTimeMillis();
389

    
390
            System.out.println("Aggregations request through rest template took " + (end - start) + "ms");
391
            JSONObject repository = new JSONObject(rs);
392

    
393
            if (repository.getJSONArray("datasourceInfo").length() == 0)
394
                return aggregationHistory;
395

    
396
            start = System.currentTimeMillis();
397
            aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
398
            end = System.currentTimeMillis();
399

    
400
            System.out.println("Getting aggregations history from json " + (end - start) + "ms");
401
            return aggregationHistory.size() == 0 ? aggregationHistory : aggregationHistory.stream()
402
                    .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
403
                    .limit(size)
404
                    .collect(Collectors.toList());
405
        } catch (JSONException e) {
406
            LOGGER.debug("Exception on getRepositoryAggregations", e);
407
            emailUtils.reportException(e);
408
            throw e;
409
        }
410

    
411
    }
412

    
413
    @Override
414
    public Map<String, List<AggregationDetails>> getRepositoryAggregationsByYear(String id) throws JSONException {
415
        LOGGER.debug("Retreiving aggregations (by year) for repository with id : " + id);
416
        UriComponents uriComponents = searchDatasource("0", "100");
417
        RequestFilter requestFilter = new RequestFilter();
418
        requestFilter.setId(id);
419

    
420
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
421
        Map<String, List<AggregationDetails>> aggregationByYear = new HashMap<>();
422
        try {
423
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
424
            JSONObject repository = new JSONObject(rs);
425

    
426
            if (repository.getJSONArray("datasourceInfo").length() == 0)
427
                return aggregationByYear;
428

    
429
            aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
430
            return aggregationHistory.size() == 0 ? aggregationByYear : createYearMap(aggregationHistory);
431

    
432
        } catch (JSONException e) {
433
            LOGGER.debug("Exception on getRepositoryAggregations", e);
434
            emailUtils.reportException(e);
435
            throw e;
436
        }
437
    }
438

    
439
    private Map<String, List<AggregationDetails>> createYearMap(List<AggregationDetails> aggregationHistory) {
440
        Map<String, List<AggregationDetails>> aggregationByYear;
441
        aggregationHistory = aggregationHistory.stream()
442
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
443
                .collect(Collectors.toList());
444

    
445
        return aggregationHistory.stream()
446
                .collect(Collectors.groupingBy(AggregationDetails::getYear));
447
    }
448

    
449

    
450
    @Override
451
    public List<Repository> getRepositoriesByName(String name,
452
                                                  String page,
453
                                                  String size) throws JSONException {
454

    
455
        LOGGER.debug("Retreiving  repositories with official name : " + name);
456
        UriComponents uriComponents = searchDatasource("0", "100");
457
        RequestFilter requestFilter = new RequestFilter();
458
        requestFilter.setOfficialname(name);
459

    
460
        try {
461
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
462
            List<Repository> repos = Converter.jsonToRepositoryList(new JSONObject(rs));
463
            for (Repository r : repos)
464
                updateRepositoryInfo(r);
465
            return repos;
466
        } catch (Exception e) {
467
            LOGGER.debug("Exception on getRepositoriesByName", e);
468
            emailUtils.reportException(e);
469
            throw e;
470
        }
471

    
472
    }
473

    
474
    @Override
475
    public List<RepositoryInterface> getRepositoryInterface(String id) throws JSONException {
476

    
477
        UriComponents uriComponents = UriComponentsBuilder
478
                .fromHttpUrl(baseAddress + "/ds/api/")
479
                .path("/{id}")
480
                .build().expand(id).encode();
481

    
482
        try {
483
            String rs = restTemplate.getForObject(uriComponents.toUri(), String.class);
484
            return Converter.jsonToRepositoryInterfaceList(new JSONObject(rs));
485
        } catch (Exception e) {
486
            LOGGER.debug("Exception on getRepositoryInterface", e);
487
            emailUtils.reportException(e);
488
            throw e;
489
        }
490

    
491
    }
492

    
493
    @Override
494
    public Repository addRepository(String datatype,
495
                                    Repository repository) throws Exception {
496

    
497
        LOGGER.debug("storing " + datatype + " repository with id: " + repository.getId());
498

    
499
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
500
        repository.setActivationId(UUID.randomUUID().toString());
501
        repository.setCollectedFrom("infrastruct_::openaire");
502

    
503
        if (datatype.equals("journal")) {
504
            repository.setId("openaire____::issn" + repository.getIssn());
505
            repository.setNamespacePrefix("issn" + repository.getIssn());
506
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
507
        } else if (datatype.equals("aggregator")) {
508
            repository.setId("openaire____::" + com.unboundid.util.Base64.encode(repository.getOfficialName()));
509
            repository.setNamespacePrefix(DigestUtils.md5Hex(repository.getOfficialName()).substring(0, 12));
510
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
511
        } else {
512
            this.latentUpdate(repository, SecurityContextHolder.getContext().getAuthentication());
513
        }
514

    
515
        // TODO: move the following code elsewhere (creation and assignment of role to user) ??
516
        // Create new role
517
        String newRoleName = roleMappingService.getRoleIdByRepoId(repository.getId());
518
        Role newRole = new Role(newRoleName, repository.getOfficialName());
519
        Integer couId = null;
520
        try {
521
            couId = registryCalls.createRole(newRole);
522
        } catch (HttpClientErrorException e) {
523
            couId = registryCalls.getCouId(newRoleName);
524
            if (couId == null) {
525
                LOGGER.error(String.format("Could not create role '%s'", newRoleName), e);
526
            }
527
        } catch (Exception e) {
528
            LOGGER.error(String.format("Could not create role '%s'", newRoleName), e);
529
            throw e;
530
        }
531

    
532
        // Assign new role to the user that created it
533
        Integer coPersonId = registryCalls.getCoPersonIdByIdentifier();
534
        if (couId != null) {
535
            Integer role = registryCalls.getRoleId(coPersonId, couId);
536
            try {
537
                registryCalls.assignMemberRole(coPersonId, couId, role);
538

    
539
                // Add role to current user authorities
540
                authoritiesUpdater.addRole(roleMappingService.convertRepoIdToAuthority(repository.getId()));
541
            } catch (Exception e) {
542
                LOGGER.debug("Exception on assign role to user during add repository", e);
543
                throw e;
544
            }
545

    
546
        }
547

    
548

    
549
        return repository;
550
    }
551

    
552
    /* update method acting as add -> send email with registration topic/body*/
553
    private Repository latentUpdate(Repository repository, Authentication authentication) throws Exception {
554
        UriComponents uriComponents = UriComponentsBuilder
555
                .fromHttpUrl(baseAddress + "/ds/update/")
556
                .build()
557
                .encode();
558

    
559
        try {
560
            String json_repository = Converter.repositoryObjectToJson(repository);
561
            LOGGER.debug("JSON to add(update) -> " + json_repository);
562

    
563
            HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
564
            ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
565

    
566
            if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
567
//                emailUtils.sendUserRegistrationEmail(repository, authentication);
568
//                emailUtils.sendAdminRegistrationEmail(repository, authentication);
569
            } else
570
                LOGGER.debug(responseEntity.getBody().toString());
571

    
572
            return repository;
573
        } catch (Exception e) {
574
            LOGGER.debug("Exception on updateRepository", e);
575
            emailUtils.reportException(e);
576
            throw e;
577
        }
578

    
579

    
580
    }
581

    
582
    @Override
583
    public Repository updateRepository(Repository repository, Authentication authentication) throws Exception {
584
        UriComponents uriComponents = UriComponentsBuilder
585
                .fromHttpUrl(baseAddress + "/ds/update/")
586
                .build()
587
                .encode();
588

    
589
        try {
590
            String json_repository = Converter.repositoryObjectToJson(repository);
591

    
592
            LOGGER.debug("JSON to update -> " + json_repository);
593

    
594
            HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
595
            ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity
596
                    , ResponseEntity.class);
597

    
598
            if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
599
                emailUtils.sendUserUpdateRepositoryInfoEmail(repository, authentication);
600
                emailUtils.sendAdminUpdateRepositoryInfoEmail(repository, authentication);
601
            } else
602
                LOGGER.debug(responseEntity.getBody().toString());
603

    
604
            return repository;
605
        } catch (Exception e) {
606
            LOGGER.debug("Exception on updateRepository", e);
607
            emailUtils.reportException(e);
608
            throw e;
609
        }
610
    }
611

    
612
    private void storeRepository(Repository repository, Authentication authentication) throws Exception {
613

    
614
        Date utilDate = new Date();
615
        Timestamp date = new Timestamp(utilDate.getTime());
616
        repository.setDateOfCollection(date);
617
        repository.setAggregator("OPENAIRE");
618
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
619

    
620
        UriComponents uriComponents = UriComponentsBuilder
621
                .fromHttpUrl(baseAddress + "/ds/add/")
622
                .build()
623
                .encode();
624
        String json_repository = Converter.repositoryObjectToJson(repository);
625
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
626
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
627

    
628
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
629
            emailUtils.sendUserRegistrationEmail(repository, authentication);
630
            emailUtils.sendAdminRegistrationEmail(repository, authentication);
631
        } else {
632
            LOGGER.debug(responseEntity.getBody().toString());
633
        }
634
    }
635

    
636
    @Override
637
    public void deleteRepositoryInterface(String id,
638
                                          String registeredBy) {
639
        UriComponents uriComponents = UriComponentsBuilder
640
                .fromHttpUrl(baseAddress + "/ds/api/")
641
                .path("/{id}")
642
                .build().expand(id).encode();
643
        LOGGER.debug(uriComponents.toUri());
644
        restTemplate.delete(uriComponents.toUri());
645
    }
646

    
647
    @Override
648
    public RepositoryInterface addRepositoryInterface(String datatype,
649
                                                      String repoId,
650
                                                      String registeredBy,
651
                                                      String comment, RepositoryInterface repositoryInterface) throws Exception {
652
        try {
653
            Repository e = this.getRepositoryById(repoId);
654
            repositoryInterface = createRepositoryInterface(e, repositoryInterface, datatype);
655
            String json_interface = Converter.repositoryInterfaceObjectToJson(e, repositoryInterface);
656

    
657
            UriComponents uriComponents = UriComponentsBuilder
658
                    .fromHttpUrl(baseAddress + "/ds/api/add/")
659
                    .build()
660
                    .encode();
661

    
662
            HttpEntity<String> httpEntity = new HttpEntity<>(json_interface, httpHeaders);
663

    
664
            restTemplate.postForObject(uriComponents.toUri(), httpEntity, String.class);
665

    
666
            emailUtils.sendAdminRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
667
            emailUtils.sendUserRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
668

    
669
            submitInterfaceValidation(e, registeredBy, repositoryInterface, false);
670

    
671
            return repositoryInterface;
672

    
673
        } catch (Exception e) {
674
            LOGGER.error("Exception on addRepositoryInterface", e);
675
            emailUtils.reportException(e);
676
            throw e;
677
        }
678
    }
679

    
680
    @Override
681
    public RepositoryInterface updateRepositoryInterface(String repoId,
682
                                                         String registeredBy,
683
                                                         String comment, RepositoryInterface repositoryInterface) throws Exception {
684

    
685
        this.updateBaseUrl(repoId, repositoryInterface.getId(), repositoryInterface.getBaseUrl());
686
        this.updateCompliance(repoId, repositoryInterface.getId(), repositoryInterface.getCompliance());
687
        this.updateValidationSet(repoId, repositoryInterface.getId(), repositoryInterface.getAccessSet());
688

    
689
        Repository repository = this.getRepositoryById(repoId);
690
        try {
691
            emailUtils.sendAdminUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
692
            emailUtils.sendUserUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
693
        } catch (Exception e) {
694
            LOGGER.warn("Could not send emails", e);
695
        }
696

    
697
        submitInterfaceValidation(getRepositoryById(repoId), registeredBy, repositoryInterface, true);
698

    
699
        return repositoryInterface;
700
    }
701

    
702
    private void submitInterfaceValidation(Repository repo, String userEmail, RepositoryInterface iFace, boolean updateExisting) throws ValidatorServiceException {
703
        JobForValidation job = new JobForValidation();
704

    
705
        job.setActivationId(UUID.randomUUID().toString());
706
        job.setAdminEmails(Collections.singletonList(this.adminEmail));
707
        job.setBaseUrl(iFace.getBaseUrl());
708
        job.setDatasourceId(repo.getId());
709
        job.setDesiredCompatibilityLevel(iFace.getDesiredCompatibilityLevel());
710
        job.setInterfaceId(iFace.getId());
711
        job.setOfficialName(repo.getOfficialName());
712
        job.setRepoType(repo.getDatasourceType());
713
        job.setUserEmail(userEmail);
714
        job.setValidationSet((iFace.getAccessSet().isEmpty() ? "none" : iFace.getAccessSet()));
715
        job.setRecords(-1);
716
        job.setRegistration(!updateExisting);
717
        job.setUpdateExisting(updateExisting);
718

    
719
        this.validatorService.submitJobForValidation(job);
720
    }
721

    
722
    private RepositoryInterface createRepositoryInterface(Repository repo, RepositoryInterface iFace, String datatype) {
723

    
724
        iFace.setContentDescription("metadata");
725
        iFace.setCompliance("UNKNOWN");
726

    
727
        if (datatype.equals("re3data"))
728
            iFace.setAccessFormat("oai_datacite");
729
        else
730
            iFace.setAccessFormat("oai_dc");
731

    
732

    
733
        if (repo.getDatasourceClass() != null && !repo.getDatasourceClass().isEmpty())
734
            iFace.setTypology(repo.getDatasourceClass());
735
        else if (datatype.equalsIgnoreCase("journal"))
736
            iFace.setTypology("pubsrepository::journal");
737
        else if (datatype.equalsIgnoreCase("aggregator"))
738
            iFace.setTypology("aggregator::pubsrepository::unknown");
739
        else if (datatype.equalsIgnoreCase("opendoar"))
740
            iFace.setTypology("pubsrepository::unknown");
741
        else if (datatype.equalsIgnoreCase("re3data"))
742
            iFace.setTypology("datarepository::unknown");
743

    
744
        iFace.setRemovable(true);
745
        iFace.setAccessProtocol("oai");
746
        iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
747
        iFace.setId("api_________::" + repo.getId() + "::" + UUID.randomUUID().toString().substring(0, 8));
748
        if (iFace.getAccessSet() == null || iFace.getAccessSet().isEmpty()) {
749
            LOGGER.debug("set is empty: " + iFace.getAccessSet());
750
            iFace.removeAccessSet();
751
            iFace.setAccessSet("none");
752
        }
753
        return iFace;
754
    }
755

    
756
    @Override
757
    public List<String> getDnetCountries() {
758
        LOGGER.debug("Getting dnet-countries!");
759
        return Converter.readFile("countries.txt");
760
    }
761

    
762
    @Override
763
    public List<String> getTypologies() {
764
        return Converter.readFile("typologies.txt");
765
    }
766

    
767
    @Override
768
    public List<Timezone> getTimezones() {
769
        List<String> timezones = Converter.readFile("timezones.txt");
770
        return Converter.toTimezones(timezones);
771
    }
772

    
773
    @Override
774
    public List<String> getUrlsOfUserRepos(String userEmail,
775
                                           String page,
776
                                           String size) {
777
        UriComponents uriComponents = UriComponentsBuilder
778
                .fromHttpUrl(baseAddress + "/api/baseurl/")
779
                .path("/{page}/{size}")
780
                .build().expand(page, size).encode();
781

    
782
        try {
783
            RequestFilter requestFilter = new RequestFilter();
784
            requestFilter.setRegisteredby(userEmail);
785
            return Arrays.asList(restTemplate.postForObject(uriComponents.toUri(), requestFilter, String[].class));
786
        } catch (Exception e) {
787
            LOGGER.debug("Exception on addRepositoryInterface", e);
788
            emailUtils.reportException(e);
789
            throw e;
790
        }
791
    }
792

    
793
    @Override
794
    public List<String> getDatasourceVocabularies(String mode) {
795

    
796
        List<String> resultSet = new ArrayList<>();
797
        for (Map.Entry<String, String> entry : this.getVocabulary("dnet:datasource_typologies").getAsMap().entrySet()) {
798
            if (mode.equalsIgnoreCase("aggregator")) {
799
                if (entry.getKey().contains("aggregator"))
800
                    resultSet.add(entry.getValue());
801
            } else if (mode.equalsIgnoreCase("journal")) {
802
                if (entry.getKey().contains("journal"))
803
                    resultSet.add(entry.getValue());
804
            } else if (mode.equalsIgnoreCase("opendoar")) {
805
                if (entry.getKey().contains("pubsrepository"))
806
                    resultSet.add(entry.getValue());
807
            } else if (mode.equalsIgnoreCase("re3data")) {
808
                if (entry.getKey().contains("datarepository"))
809
                    resultSet.add(entry.getValue());
810
            }
811
        }
812

    
813

    
814
        return resultSet;
815
    }
816

    
817
    private Vocabulary getVocabulary(String vocName) {
818

    
819
        if (!vocabularyMap.containsKey(vocName)) {
820
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
821
        }
822
        return vocabularyMap.get(vocName);
823
    }
824

    
825

    
826
    @Override
827
    public Map<String, String> getCompatibilityClasses(String mode) {
828

    
829
        LOGGER.debug("Getting compatibility classes for mode: " + mode);
830
        Map<String, String> retMap = new HashMap<String, String>();
831

    
832
        Map<String, String> compatibilityClasses = this.getVocabulary("dnet:compatibilityLevel").getAsMap();
833
        boolean foundData = false;
834
        for (Map.Entry<String, String> entry : compatibilityClasses.entrySet()) {
835
            if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_ALL))
836
                return compatibilityClasses;
837
            else if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_RE3DATA)) {
838
                if (entry.getKey().matches("^openaire[1-9].0_data$")) {
839
                    retMap.put(entry.getKey(), entry.getValue());
840
                    foundData = true;
841
                }
842
            } else {
843
                if (entry.getKey().matches("^openaire[1-9].0$") || entry.getKey().equals("driver"))
844
                    retMap.put(entry.getKey(), entry.getValue());
845
            }
846
        }
847

    
848
        //TODO TO BE REMOVED WHEN VOCABULARIES ARE UPDATED
849
        if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_RE3DATA) && !foundData)
850
            retMap.put("openaire2.0_data", "OpenAIRE Data (funded, referenced datasets)");
851

    
852
        return retMap;
853
    }
854

    
855
    @Override
856
    public Map<String, String> getDatasourceClasses(String mode) {
857

    
858
        LOGGER.debug("Getting datasource classes for mode: " + mode);
859

    
860
        Map<String, String> retMap = new HashMap<String, String>();
861

    
862
        for (Map.Entry<String, String> entry : this.getVocabulary("dnet:datasource_typologies").getAsMap().entrySet()) {
863
            if (mode.equalsIgnoreCase("aggregator")) {
864
                if (entry.getKey().contains("aggregator"))
865
                    retMap.put(entry.getKey(), entry.getValue());
866
            } else if (mode.equalsIgnoreCase("journal")) {
867
                if (entry.getKey().contains("journal"))
868
                    retMap.put(entry.getKey(), entry.getValue());
869
            } else if (mode.equalsIgnoreCase("opendoar")) {
870
                if (entry.getKey().contains("pubsrepository"))
871
                    retMap.put(entry.getKey(), entry.getValue());
872
            } else if (mode.equalsIgnoreCase("re3data")) {
873
                if (entry.getKey().contains("datarepository"))
874
                    retMap.put(entry.getKey(), entry.getValue());
875
            }
876
        }
877
        return filterResults(retMap, mode);
878

    
879
    }
880

    
881
    private Map<String, String> filterResults(Map<String, String> map, String mode) {
882

    
883
        HashMap<String, String> filteredMap = new HashMap<>();
884
        for (String key : map.keySet())
885
            if (dataSourceClass.get(mode).contains(key))
886
                filteredMap.put(key, map.get(key));
887

    
888
        return filteredMap;
889
    }
890

    
891
    @Override
892
    public String getCountryName(String countryCode) {
893
        return inverseCountriesMap.get(countryCode);
894
    }
895

    
896
    @Override
897
    public MetricsInfo getMetricsInfoForRepository(String repoId) throws RepositoryServiceException {
898
        try {
899

    
900
            MetricsInfo metricsInfo = new MetricsInfo();
901
            metricsInfo.setDiagramsBaseURL(this.usageStatisticsDiagramsBaseURL);
902
            metricsInfo.setMetricsNumbers(getMetricsNumbers(getOpenAIREId(repoId)));
903
            return metricsInfo;
904

    
905
        } catch (Exception e) {
906
            LOGGER.error("Error while getting metrics info for repository: ", e);
907
            emailUtils.reportException(e);
908
            throw new RepositoryServiceException("General error", RepositoryServiceException.ErrorCode.GENERAL_ERROR);
909
        }
910
    }
911

    
912
    @Override
913
    public Map<String, String> getListLatestUpdate(String mode) throws JSONException {
914
        if (mode.equals("opendoar"))
915
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(0).getLastCollectionDate());
916
        else
917
            /*
918
             * first api of re3data has null value on collection date
919
             * */
920
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(1).getLastCollectionDate());
921
    }
922

    
923
    private void updateValidationSet(String repositoryId, String repositoryInterfaceId, String validationSet) throws Exception {
924
        UriComponents uriComponents = UriComponentsBuilder
925
                .fromHttpUrl(baseAddress + "/ds/api/oaiset")
926
                .queryParam("dsId", repositoryId)
927
                .queryParam("apiId", repositoryInterfaceId)
928
                .queryParam("oaiSet", validationSet)
929
                .build().encode();
930
        restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, null, ResponseEntity.class);
931

    
932
    }
933

    
934

    
935
    private void updateBaseUrl(String repositoryId, String repositoryInterfaceId, String baseUrl) {
936
        UriComponents uriComponents = UriComponentsBuilder
937
                .fromHttpUrl(baseAddress + "/ds/api/baseurl")
938
                .queryParam("dsId", repositoryId)
939
                .queryParam("apiId", repositoryInterfaceId)
940
                .queryParam("baseUrl", baseUrl)
941
                .build().encode();
942
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
943
    }
944

    
945
    private void updateCompliance(String repositoryId, String repositoryInterfaceId, String compliance) {
946
        UriComponents uriComponents = UriComponentsBuilder
947
                .fromHttpUrl(baseAddress + "/ds/api/compliance")
948
                .queryParam("dsId", repositoryId)
949
                .queryParam("apiId", repositoryInterfaceId)
950
                .queryParam("compliance", compliance)
951
                .build().encode();
952
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
953
    }
954

    
955
    private MetricsNumbers getMetricsNumbers(String openAIREID) throws BrokerException {
956

    
957
        //build the uri params
958
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(this.usageStatisticsNumbersBaseURL + openAIREID + "/clicks");
959

    
960
        //create new template engine
961
        RestTemplate template = new RestTemplate();
962
        template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
963
        ResponseEntity<MetricsNumbers> resp;
964
        try {
965
            //communicate with endpoint
966
            resp = template.exchange(
967
                    builder.build().encode().toUri(),
968
                    HttpMethod.GET,
969
                    null,
970
                    new ParameterizedTypeReference<MetricsNumbers>() {
971
                    });
972
        } catch (RestClientException e) {
973
            LOGGER.debug("Exception on getMetricsNumbers", e);
974
            emailUtils.reportException(e);
975
            throw e;
976
        }
977

    
978
        return resp.getBody();
979
    }
980

    
981
    private String getOpenAIREId(String repoId) {
982

    
983
        if (repoId != null && repoId.contains("::")) {
984
            return repoId.split("::")[0] + "::" + DigestUtils.md5Hex(repoId.split("::")[1]);
985
        }
986

    
987
        return null;
988
    }
989

    
990
    private UriComponents searchDatasource(String page, String size) {
991

    
992
        return UriComponentsBuilder
993
                .fromHttpUrl(baseAddress + "/ds/search/")
994
                .path("/{page}/{size}/")
995
                .queryParam("requestSortBy", "officialname")
996
                .queryParam("order", "ASCENDING")
997
                .build().expand(page, size).encode();
998
    }
999

    
1000
    private UriComponents searchSnipperDatasource(String page, String size) {
1001

    
1002
        return UriComponentsBuilder
1003
                .fromHttpUrl(baseAddress + "/ds/searchsnippet/")
1004
                .path("/{page}/{size}/")
1005
                .queryParam("requestSortBy", "officialname")
1006
                .queryParam("order", "ASCENDING")
1007
                .build().expand(page, size).encode();
1008
    }
1009

    
1010
    private UriComponents searchRegisteredDatasource(String requestSortBy, String order, String page, String size) {
1011

    
1012
        return UriComponentsBuilder
1013
                .fromHttpUrl(baseAddress + "/ds/searchregistered/")
1014
                .path("/{page}/{size}/")
1015
                .queryParam("requestSortBy", requestSortBy)
1016
                .queryParam("order", order)
1017
                .build().expand(page, size).encode();
1018
    }
1019

    
1020
    private String getRepositoryType(String typology) {
1021
        return invertedDataSourceClass.get(typology);
1022
    }
1023

    
1024
    private List<String> getRoleIdsFromUserRoles(String userEmail) {
1025
        Integer coPersonId = registryCalls.getCoPersonIdByEmail(userEmail);
1026
        JsonArray roles;
1027
        ArrayList<String> roleIds = new ArrayList<>();
1028
        ArrayList<Integer> couIds = new ArrayList<>();
1029
        if (coPersonId != null) {
1030
            roles = registryCalls.getRoles(coPersonId);
1031
            for (JsonElement role : roles) {
1032
                JsonObject object = role.getAsJsonObject();
1033
                if (object.get("CouId") == null) {
1034
                    continue;
1035
                }
1036
                couIds.add(object.get("CouId").getAsInt());
1037
            }
1038

    
1039
            roleIds.addAll(registryCalls.getCouNames(couIds).values());
1040

    
1041
        }
1042
        return roleIds;
1043
    }
1044

    
1045
    private List<String> getRepoIdsFromUserRoles(String userEmail) {
1046
        List<String> roleIds = getRoleIdsFromUserRoles(userEmail);
1047
        List<String> repoIds = new ArrayList<>();
1048
        for (String role : roleIds) {
1049
            if (role.contains("datasource")) {
1050
                // TODO: ask if checking for BETA prefix is required
1051
                repoIds.add(role.replaceFirst(".*datasource\\.", "").replace("$", ":"));
1052
            }
1053
        }
1054
        return repoIds;
1055
    }
1056
}
(12-12/20)