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.AuthoritiesUpdater;
17
import eu.dnetlib.repo.manager.service.security.AuthorizationService;
18
import eu.dnetlib.repo.manager.service.security.RoleMappingService;
19
import eu.dnetlib.repo.manager.utils.Converter;
20
import gr.uoa.di.driver.enabling.vocabulary.VocabularyLoader;
21
import org.apache.commons.codec.digest.DigestUtils;
22
import org.apache.log4j.Logger;
23
import org.json.JSONArray;
24
import org.json.JSONException;
25
import org.json.JSONObject;
26
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
27
import org.springframework.beans.factory.annotation.Autowired;
28
import org.springframework.beans.factory.annotation.Value;
29
import org.springframework.context.annotation.Lazy;
30
import org.springframework.core.ParameterizedTypeReference;
31
import org.springframework.http.*;
32
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
33
import org.springframework.security.core.Authentication;
34
import org.springframework.security.core.context.SecurityContextHolder;
35
import org.springframework.stereotype.Service;
36
import org.springframework.web.client.HttpClientErrorException;
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 AuthorizationService authorizationService;
54
    private final RoleMappingService roleMappingService;
55
    private final AaiRegistryService registryCalls;
56
    private final AuthoritiesUpdater authoritiesUpdater;
57
    private final RestTemplate restTemplate;
58
    private final VocabularyLoader vocabularyLoader;
59
    private final PiWikService piWikService;
60
    private final EmailUtils emailUtils;
61
    private final ValidatorService validatorService;
62

    
63
    @Value("${services.provide.clients.dsm}")
64
    private String baseAddress;
65

    
66
    @Value("${services.provide.adminEmail}")
67
    private String adminEmail;
68

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

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

    
75

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

    
79

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

    
85
    private HttpHeaders httpHeaders;
86

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

    
108
    private String getAuthenticatedUserEmail() {
109
        OIDCAuthenticationToken authenticationToken = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
110
        return authenticationToken.getUserInfo().getEmail();
111
    }
112

    
113

    
114
    @PostConstruct
115
    private void init() {
116
        LOGGER.debug("Initialization method of repository api!");
117
        LOGGER.debug("Updated version!");
118

    
119
        for (String key : this.getVocabulary("dnet:datasource_typologies").getAsMap().keySet()) {
120
            if (key.contains("aggregator")) {
121
                dataSourceClass.putIfAbsent("aggregator", new ArrayList<>());
122
                dataSourceClass.get("aggregator").add(key);
123
            } else if (key.contains("crissystem")) {
124
                dataSourceClass.putIfAbsent("cris", new ArrayList<>());
125
                dataSourceClass.get("cris").add(key);
126
            } else if (key.contains("pubsrepository::journal")) { // do not change order -->
127
                dataSourceClass.putIfAbsent("journal", Collections.singletonList("pubsrepository::journal"));
128
            } else if (key.contains("pubsrepository")) { // do not change order <--
129
                dataSourceClass.putIfAbsent("opendoar", new ArrayList<>());
130
                dataSourceClass.get("opendoar").add(key);
131
            } else if (key.contains("datarepository")) {
132
                dataSourceClass.putIfAbsent("re3data", Collections.singletonList("datarepository::unknown"));
133
            } else if (key.contains("pubsrepository::journal")) {
134
                dataSourceClass.putIfAbsent("journal", Collections.singletonList("pubsrepository::journal"));
135
            }
136
        }
137

    
138
        for (Map.Entry<String, List<String>> entry : dataSourceClass.entrySet()) {
139
            entry.getValue().forEach(v -> invertedDataSourceClass.put(v, entry.getKey()));
140
        }
141

    
142
        httpHeaders = new HttpHeaders();
143
        httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
144

    
145
        for (String vocName : vocabularyNames) {
146
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
147
        }
148

    
149
        Country[] countries = getCountries();
150
        for (Country c : countries) {
151
            countriesMap.put(c.getName(), c.getCode());
152
            inverseCountriesMap.put(c.getCode(), c.getName());
153
        }
154

    
155

    
156
    }
157

    
158
    @Override
159
    public Country[] getCountries() {
160
        UriComponents uriComponents = UriComponentsBuilder
161
                .fromHttpUrl(baseAddress + "/ds/countries")
162
                .build().encode();
163
        return restTemplate.getForObject(uriComponents.toUri(), Country[].class);
164
    }
165
    
166
    // FIXME: with the new roles of the users the "requestFilter.setRegisteredby(userEmail)" can no longer be used
167
    //  and the "requestFilter.setId(repoId)" should return only one result at a time, thus,
168
    //  another way for paging must be implemented.
169
    @Override
170
    public List<Repository> getRepositories(List<String> ids) throws JSONException {
171
        return getRepositories(ids, 0, 10);
172
    }
173

    
174
    // FIXME: with the new roles of the users the "requestFilter.setRegisteredby(userEmail)" can no longer be used
175
    //  and the "requestFilter.setId(repoId)" should return only one result at a time, thus,
176
    //  another way for paging must be implemented.
177
    @Override
178
    public List<Repository> getRepositories(List<String> ids, int page, int size) throws JSONException {
179
        List<Repository> repos = new ArrayList<>();
180
        LOGGER.debug("Retreiving repositories with ids : " + String.join(", ", ids));
181
        UriComponents uriComponents = searchDatasource(Integer.toString(Math.abs(page)), Integer.toString(Math.abs(size)));
182
        RequestFilter requestFilter = new RequestFilter();
183

    
184
        for (String repoId : ids) {
185
            requestFilter.setId(repoId);
186
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
187

    
188
            repos.addAll(Converter.jsonToRepositoryList(new JSONObject(rs)));
189
        }
190

    
191
        for (Repository r : repos)
192
            r.setPiwikInfo(piWikService.getPiwikSiteForRepo(r.getId()));
193
        return repos;
194
    }
195

    
196
    // FIXME: with the new roles of the users the "requestFilter.setRegisteredby(userEmail)" can no longer be used
197
    //  and the "requestFilter.setId(repoId)" should return only one result at a time, thus,
198
    //  another way for paging must be implemented.
199
    @Override
200
    public List<RepositorySnippet> getRepositoriesSnippets(List<String> ids) throws Exception {
201
        return getRepositoriesSnippets(ids, 0, 10);
202
    }
203

    
204
    // FIXME: with the new roles of the users the "requestFilter.setRegisteredby(userEmail)" can no longer be used
205
    //  and the "requestFilter.setId(repoId)" should return only one result at a time, thus,
206
    //  another way for paging must be implemented.
207
    @Override
208
    public List<RepositorySnippet> getRepositoriesSnippets(List<String> ids, int page, int size) throws Exception {
209
        List<RepositorySnippet> resultSet = new ArrayList<>();
210
        ObjectMapper mapper = new ObjectMapper();
211

    
212
        // here page should be 0
213
        UriComponents uriComponents = searchSnipperDatasource(Integer.toString(Math.abs(page)), Integer.toString(Math.abs(size)));
214
        RequestFilter requestFilter = new RequestFilter();
215

    
216
        try {
217
            for (String repoId : ids) {
218
                requestFilter.setId(repoId);
219

    
220
                String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
221
                JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
222
                resultSet.addAll(mapper.readValue(String.valueOf(jsonArray),
223
                        mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
224
            }
225
        } catch (Exception e) {
226
            LOGGER.debug("Exception on getRepositoriesSnippetOfUser", e);
227
            throw e;
228
        }
229

    
230
        LOGGER.debug("resultSet:" + resultSet);
231
        resultSet.parallelStream().forEach(repositorySnippet -> {
232
            repositorySnippet.setPiwikInfo(piWikService.getPiwikSiteForRepo(repositorySnippet.getId()));
233
        });
234
        return resultSet;
235
    }
236

    
237

    
238
    @Override
239
    public List<RepositorySnippet> getRepositoriesByCountry(String country,
240
                                                            String mode,
241
                                                            Boolean managed) throws JSONException, IOException {
242

    
243
        LOGGER.debug("Getting repositories by country!");
244
        int page = 0;
245
        int size = 100;
246
        List<RepositorySnippet> resultSet = new ArrayList<>();
247
        ObjectMapper mapper = new ObjectMapper();
248

    
249
        String filterKey = "UNKNOWN";
250
        if (mode.equalsIgnoreCase("opendoar"))
251
            filterKey = "openaire____::opendoar";
252
        else if (mode.equalsIgnoreCase("re3data"))
253
            filterKey = "openaire____::re3data";
254
        else if (mode.equalsIgnoreCase("cris"))
255
            filterKey = "eurocrisdris::dris";
256

    
257

    
258
        LOGGER.debug("Country code equals : " + country);
259
        LOGGER.debug("Filter mode equals : " + filterKey);
260

    
261
        UriComponents uriComponents = searchSnipperDatasource(String.valueOf(page), String.valueOf(size));
262
        RequestFilter requestFilter = new RequestFilter();
263
        requestFilter.setCountry(country);
264
        requestFilter.setCollectedfrom(filterKey);
265

    
266
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
267
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
268
        while (jsonArray.length() > 0) {
269

    
270
LOGGER.debug("json: " + jsonArray);
271

    
272
            resultSet.addAll(mapper.readValue(String.valueOf(jsonArray),
273
                    mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
274
            page += 1;
275
            uriComponents = searchSnipperDatasource(String.valueOf(page), String.valueOf(size));
276
            rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
277
            jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
278
        }
279
        return resultSet;
280
    }
281

    
282
    public List<RepositorySnippet> searchRegisteredRepositories(String country, String typology, String englishName,
283
                                                                String officialName, String requestSortBy, String order, int page, int pageSize) throws Exception {
284

    
285
        LOGGER.debug("Searching registered repositories");
286

    
287
        List<RepositorySnippet> resultSet = new ArrayList<>();
288
        ObjectMapper mapper = new ObjectMapper();
289

    
290
        UriComponents uriComponents = searchRegisteredDatasource(requestSortBy, order, Integer.toString(page), Integer.toString(pageSize));
291

    
292
        RequestFilter requestFilter = new RequestFilter();
293
        requestFilter.setCountry(country);
294
        requestFilter.setTypology(typology);
295
        requestFilter.setOfficialname(officialName);
296
        requestFilter.setEnglishname(englishName);
297

    
298
        try {
299
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
300
            JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
301

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

    
304
            return resultSet;
305
        } catch (Exception e) {
306
            LOGGER.error("Error searching registered datasources", e);
307
            throw e;
308
        }
309
    }
310

    
311
    @Override
312
    public int getTotalRegisteredRepositories() {
313
        UriComponents uriComponents = UriComponentsBuilder
314
                .fromHttpUrl(baseAddress + "/ds/countregistered")
315
                .queryParam("fromDate", "1900-01-01")
316
                .build().encode();
317

    
318
        return restTemplate.getForObject(uriComponents.toUri(), Integer.class);
319
    }
320

    
321
    private Repository updateRepositoryInfo(Repository r) throws JSONException {
322

    
323
        /*
324
         * from datasource class
325
         * we get the datasource type form the inverted map
326
         * */
327
        r.setDatasourceType(getRepositoryType(r.getDatasourceClass()));
328
        r.setInterfaces(this.getRepositoryInterface(r.getId()));
329
        r.setPiwikInfo(piWikService.getPiwikSiteForRepo(r.getId()));
330
        r.setCountryName(getCountryName(r.getCountryCode()));
331
        return r;
332
    }
333

    
334

    
335
    private Collection<Repository> getRepositoriesByMode(String mode, List<Repository> rs) {
336

    
337
        List<Repository> reps = new ArrayList<>();
338
        for (Repository r : rs) {
339
            if (r.getCollectedFrom() != null && r.getCollectedFrom().equals(mode))
340
                reps.add(r);
341

    
342
        }
343
        return reps;
344
    }
345

    
346
    @Override
347
    public List<Repository> getRepositoriesOfUser(String page, String size) throws JSONException {
348
        String userEmail = ((OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication()).getUserInfo().getEmail();
349
        LOGGER.debug("Retreiving repositories of authenticated user : " + userEmail);
350
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles());
351
        return getRepositories(new ArrayList<>(repoIds));
352
    }
353

    
354
    @Override
355
    public List<Repository> getRepositoriesOfUser(String userEmail, String page, String size) throws JSONException {
356
        LOGGER.debug("Retreiving repositories of authenticated user : " + userEmail);
357
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles(userEmail));
358
        return getRepositories(new ArrayList<>(repoIds));
359
    }
360

    
361
    @Override
362
    public List<RepositorySnippet> getRepositoriesSnippetsOfUser(String page, String size) throws Exception {
363
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles());
364
        return getRepositoriesSnippets(new ArrayList<>(repoIds));
365
    }
366

    
367
    @Override
368
    public List<RepositorySnippet> getRepositoriesSnippetsOfUser(String userEmail, String page, String size) throws Exception {
369
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles(userEmail));
370
        return getRepositoriesSnippets(new ArrayList<>(repoIds));
371
    }
372

    
373
    @Override
374
    public RepositorySnippet getRepositorySnippetById(String id) throws JSONException, ResourceNotFoundException {
375

    
376
        LOGGER.debug("Retreiving repositories with id : " + id);
377
        RepositorySnippet repo = null;
378
        UriComponents uriComponents = searchSnipperDatasource("0", "100");
379
        RequestFilter requestFilter = new RequestFilter();
380
        requestFilter.setId(id);
381

    
382
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
383
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
384

    
385
        if (jsonArray.length() == 0)
386
            throw new ResourceNotFoundException();
387

    
388
        repo = Converter.jsonToRepositorySnippetObject(jsonArray.getJSONObject(0));
389
        return repo;
390
    }
391

    
392
    @Override
393
    public Repository getRepositoryById(String id) throws JSONException, ResourceNotFoundException {
394

    
395
        LOGGER.debug("Retreiving repositories with id : " + id);
396
        Repository repo = null;
397
        UriComponents uriComponents = searchDatasource("0", "100");
398
        RequestFilter requestFilter = new RequestFilter();
399
        requestFilter.setId(id);
400

    
401
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
402
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
403

    
404
        if (jsonArray.length() == 0)
405
            throw new ResourceNotFoundException();
406

    
407
        repo = Converter.jsonToRepositoryObject(jsonArray.getJSONObject(0));
408
        return updateRepositoryInfo(repo);
409
    }
410

    
411

    
412
    @Override
413
    public List<AggregationDetails> getRepositoryAggregations(String id, int from, int size) throws JSONException {
414

    
415
        LOGGER.debug("Retreiving aggregations for repository with id : " + id);
416
        UriComponents uriComponents = searchDatasource(from + "", size + "");
417
        RequestFilter requestFilter = new RequestFilter();
418
        requestFilter.setId(id);
419

    
420
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
421

    
422
        long start = System.currentTimeMillis();
423
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
424
        long end = System.currentTimeMillis();
425

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

    
429
        if (repository.getJSONArray("datasourceInfo").length() == 0)
430
            return aggregationHistory;
431

    
432
        start = System.currentTimeMillis();
433
        aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
434
        end = System.currentTimeMillis();
435

    
436
        System.out.println("Getting aggregations history from json " + (end - start) + "ms");
437
        return aggregationHistory.size() == 0 ? aggregationHistory : aggregationHistory.stream()
438
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
439
                .limit(size)
440
                .collect(Collectors.toList());
441

    
442
    }
443

    
444
    @Override
445
    public Map<String, List<AggregationDetails>> getRepositoryAggregationsByYear(String id) throws JSONException {
446
        LOGGER.debug("Retreiving aggregations (by year) for repository with id : " + id);
447
        UriComponents uriComponents = searchDatasource("0", "100");
448
        RequestFilter requestFilter = new RequestFilter();
449
        requestFilter.setId(id);
450

    
451
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
452
        Map<String, List<AggregationDetails>> aggregationByYear = new HashMap<>();
453

    
454
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
455
        JSONObject repository = new JSONObject(rs);
456

    
457
        if (repository.getJSONArray("datasourceInfo").length() == 0)
458
            return aggregationByYear;
459

    
460
        aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
461
        return aggregationHistory.size() == 0 ? aggregationByYear : createYearMap(aggregationHistory);
462
    }
463

    
464
    private Map<String, List<AggregationDetails>> createYearMap(List<AggregationDetails> aggregationHistory) {
465
        Map<String, List<AggregationDetails>> aggregationByYear;
466
        aggregationHistory = aggregationHistory.stream()
467
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
468
                .collect(Collectors.toList());
469

    
470
        return aggregationHistory.stream()
471
                .collect(Collectors.groupingBy(AggregationDetails::getYear));
472
    }
473

    
474

    
475
    @Override
476
    public List<Repository> getRepositoriesByName(String name,
477
                                                  String page,
478
                                                  String size) throws JSONException {
479

    
480
        LOGGER.debug("Retreiving  repositories with official name : " + name);
481
        UriComponents uriComponents = searchDatasource("0", "100");
482
        RequestFilter requestFilter = new RequestFilter();
483
        requestFilter.setOfficialname(name);
484

    
485
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
486
        List<Repository> repos = Converter.jsonToRepositoryList(new JSONObject(rs));
487
        for (Repository r : repos)
488
            updateRepositoryInfo(r);
489
        return repos;
490

    
491
    }
492

    
493
    @Override
494
    public List<RepositoryInterface> getRepositoryInterface(String id) throws JSONException {
495

    
496
        UriComponents uriComponents = UriComponentsBuilder
497
                .fromHttpUrl(baseAddress + "/ds/api/")
498
                .path("/{id}")
499
                .build().expand(id).encode();
500

    
501
        String rs = restTemplate.getForObject(uriComponents.toUri(), String.class);
502
        return Converter.jsonToRepositoryInterfaceList(new JSONObject(rs));
503

    
504
    }
505

    
506
    @Override
507
    public Repository addRepository(String datatype, Repository repository) throws Exception {
508

    
509
        LOGGER.debug("storing " + datatype + " repository with id: " + repository.getId());
510

    
511
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
512
        repository.setActivationId(UUID.randomUUID().toString());
513
        repository.setCollectedFrom("infrastruct_::openaire");
514

    
515
        if (datatype.equals("journal")) {
516
            repository.setId("openaire____::issn" + repository.getIssn());
517
            repository.setNamespacePrefix("issn" + repository.getIssn());
518
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
519
        } else if (datatype.equals("aggregator")) {
520
            repository.setId("openaire____::" + DigestUtils.md5Hex(repository.getOfficialName()));
521
            repository.setNamespacePrefix(DigestUtils.md5Hex(repository.getOfficialName()).substring(0, 12));
522
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
523
        } else {
524
            this.latentUpdate(repository, SecurityContextHolder.getContext().getAuthentication());
525
        }
526

    
527
        // TODO: move the following code elsewhere (creation and assignment of role to user) ??
528
        // Create new role
529
        String newRoleName = roleMappingService.getRoleIdByRepoId(repository.getId());
530
        Role newRole = new Role(newRoleName, repository.getOfficialName());
531
        Integer couId = null;
532
        try {
533
            couId = registryCalls.createRole(newRole);
534
        } catch (HttpClientErrorException e) {
535
            couId = registryCalls.getCouId(newRoleName);
536
            if (couId == null) {
537
                LOGGER.error(String.format("Could not create role '%s'", newRoleName), e);
538
            }
539
        } catch (Exception e) {
540
            LOGGER.error(String.format("Could not create role '%s'", newRoleName), e);
541
            throw e;
542
        }
543

    
544
        // Assign new role to the user that created it
545
        Integer coPersonId = registryCalls.getCoPersonIdByIdentifier();
546
        if (couId != null) {
547
            Integer role = registryCalls.getRoleId(coPersonId, couId);
548
            try {
549
                registryCalls.assignMemberRole(coPersonId, couId, role);
550

    
551
                // Add role to current user authorities
552
                authoritiesUpdater.addRole(roleMappingService.convertRepoIdToAuthority(repository.getId()));
553
            } catch (Exception e) {
554
                LOGGER.debug("Exception on assign role to user during add repository", e);
555
                throw e;
556
            }
557

    
558
        }
559

    
560

    
561
        return repository;
562
    }
563

    
564
    /* update method acting as add -> send email with registration topic/body*/
565
    private Repository latentUpdate(Repository repository, Authentication authentication) throws Exception {
566
        UriComponents uriComponents = UriComponentsBuilder
567
                .fromHttpUrl(baseAddress + "/ds/update/")
568
                .build()
569
                .encode();
570

    
571
        String json_repository = Converter.repositoryObjectToJson(repository);
572
        LOGGER.debug("JSON to add(update) -> " + json_repository);
573

    
574
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
575
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
576

    
577
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
578
            try {
579
                emailUtils.sendUserRegistrationEmail(repository, authentication);
580
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
581
            } catch (Exception e) {
582
                LOGGER.error("Error sending email", e);
583
            }
584
        } else
585
            LOGGER.error("Error storing repository: " + responseEntity.getBody().toString());
586

    
587
        return repository;
588
    }
589

    
590
    @Override
591
    public Repository updateRepository(Repository repository, Authentication authentication) throws Exception {
592
        UriComponents uriComponents = UriComponentsBuilder
593
                .fromHttpUrl(baseAddress + "/ds/update/")
594
                .build()
595
                .encode();
596

    
597
        String json_repository = Converter.repositoryObjectToJson(repository);
598

    
599
        LOGGER.debug("JSON to update -> " + json_repository);
600

    
601
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
602
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity
603
                , ResponseEntity.class);
604

    
605
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
606
            try {
607
                emailUtils.sendUserUpdateRepositoryInfoEmail(repository, authentication);
608
                emailUtils.sendAdminUpdateRepositoryInfoEmail(repository, authentication);
609
            } catch (Exception e) {
610
                LOGGER.error("Error sending emails: " + e);
611
            }
612
        } else
613
            LOGGER.debug(responseEntity.getBody().toString());
614

    
615
        return repository;
616
    }
617

    
618
    private void storeRepository(Repository repository, Authentication authentication) throws Exception {
619

    
620
        Date utilDate = new Date();
621
        Timestamp date = new Timestamp(utilDate.getTime());
622
        repository.setDateOfCollection(date);
623
        repository.setAggregator("OPENAIRE");
624
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
625

    
626
        UriComponents uriComponents = UriComponentsBuilder
627
                .fromHttpUrl(baseAddress + "/ds/add/")
628
                .build()
629
                .encode();
630
        String json_repository = Converter.repositoryObjectToJson(repository);
631
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
632
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
633

    
634
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
635
            try {
636
                emailUtils.sendUserRegistrationEmail(repository, authentication);
637
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
638
            } catch (Exception e) {
639
                LOGGER.error("Error sending emails: " + e);
640
            }
641
        } else {
642
            LOGGER.debug(responseEntity.getBody().toString());
643
        }
644
    }
645

    
646
    @Override
647
    public void deleteRepositoryInterface(String id,
648
                                          String registeredBy) {
649
        UriComponents uriComponents = UriComponentsBuilder
650
                .fromHttpUrl(baseAddress + "/ds/api/")
651
                .path("/{id}")
652
                .build().expand(id).encode();
653
        LOGGER.debug(uriComponents.toUri());
654
        restTemplate.delete(uriComponents.toUri());
655
    }
656

    
657
    @Override
658
    public RepositoryInterface addRepositoryInterface(String datatype,
659
                                                      String repoId,
660
                                                      String registeredBy,
661
                                                      String comment, RepositoryInterface repositoryInterface) throws Exception {
662
        Repository e = this.getRepositoryById(repoId);
663
        repositoryInterface = createRepositoryInterface(e, repositoryInterface, datatype);
664
        String json_interface = Converter.repositoryInterfaceObjectToJson(e, repositoryInterface);
665

    
666
        UriComponents uriComponents = UriComponentsBuilder
667
                .fromHttpUrl(baseAddress + "/ds/api/add/")
668
                .build()
669
                .encode();
670

    
671
        HttpEntity<String> httpEntity = new HttpEntity<>(json_interface, httpHeaders);
672

    
673
        restTemplate.postForObject(uriComponents.toUri(), httpEntity, String.class);
674

    
675
        try {
676
            emailUtils.sendAdminRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
677
            emailUtils.sendUserRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
678
        } catch (Exception ex) {
679
            LOGGER.error("Error sending emails: " + ex);
680
        }
681

    
682
        submitInterfaceValidation(e, registeredBy, repositoryInterface, false);
683

    
684
        return repositoryInterface;
685
    }
686

    
687
    @Override
688
    public RepositoryInterface updateRepositoryInterface(String repoId,
689
                                                         String registeredBy,
690
                                                         String comment, RepositoryInterface repositoryInterface) throws Exception {
691

    
692
        this.updateBaseUrl(repoId, repositoryInterface.getId(), repositoryInterface.getBaseUrl());
693
        this.updateCompliance(repoId, repositoryInterface.getId(), repositoryInterface.getCompliance());
694
        this.updateValidationSet(repoId, repositoryInterface.getId(), repositoryInterface.getAccessSet());
695

    
696
        Repository repository = this.getRepositoryById(repoId);
697
        try {
698
            try {
699
                emailUtils.sendAdminUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
700
                emailUtils.sendUserUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
701
            } catch (Exception e) {
702
                LOGGER.error("Error sending emails: " + e);
703
            }
704
        } catch (Exception e) {
705
            LOGGER.warn("Could not send emails", e);
706
        }
707

    
708
        submitInterfaceValidation(getRepositoryById(repoId), registeredBy, repositoryInterface, true);
709

    
710
        return repositoryInterface;
711
    }
712

    
713
    private void submitInterfaceValidation(Repository repo, String userEmail, RepositoryInterface iFace, boolean updateExisting) throws ValidatorServiceException {
714
        JobForValidation job = new JobForValidation();
715

    
716
        job.setActivationId(UUID.randomUUID().toString());
717
        job.setAdminEmails(Collections.singletonList(this.adminEmail));
718
        job.setBaseUrl(iFace.getBaseUrl());
719
        job.setDatasourceId(repo.getId());
720
        job.setDesiredCompatibilityLevel(iFace.getDesiredCompatibilityLevel());
721
        job.setInterfaceId(iFace.getId());
722
        job.setOfficialName(repo.getOfficialName());
723
        job.setRepoType(repo.getDatasourceType());
724
        job.setUserEmail(userEmail);
725
        job.setValidationSet((iFace.getAccessSet().isEmpty() ? "none" : iFace.getAccessSet()));
726
        job.setRecords(-1);
727
        job.setRegistration(!updateExisting);
728
        job.setUpdateExisting(updateExisting);
729

    
730
        this.validatorService.submitJobForValidation(job);
731
    }
732

    
733
    private RepositoryInterface createRepositoryInterface(Repository repo, RepositoryInterface iFace, String datatype) {
734

    
735
        iFace.setContentDescription("metadata");
736
        iFace.setCompliance("UNKNOWN");
737

    
738
        if (datatype.equals("re3data"))
739
            iFace.setAccessFormat("oai_datacite");
740
        else
741
            iFace.setAccessFormat("oai_dc");
742

    
743

    
744
        if (repo.getDatasourceClass() != null && !repo.getDatasourceClass().isEmpty())
745
            iFace.setTypology(repo.getDatasourceClass());
746
        else if (datatype.equalsIgnoreCase("journal"))
747
            iFace.setTypology("pubsrepository::journal");
748
        else if (datatype.equalsIgnoreCase("aggregator"))
749
            iFace.setTypology("aggregator::pubsrepository::unknown");
750
        else if (datatype.equalsIgnoreCase("opendoar"))
751
            iFace.setTypology("pubsrepository::unknown");
752
        else if (datatype.equalsIgnoreCase("re3data"))
753
            iFace.setTypology("datarepository::unknown");
754

    
755
        iFace.setRemovable(true);
756
        iFace.setAccessProtocol("oai");
757
        iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
758
        iFace.setId("api_________::" + repo.getId() + "::" + UUID.randomUUID().toString().substring(0, 8));
759
        if (iFace.getAccessSet() == null || iFace.getAccessSet().isEmpty()) {
760
            LOGGER.debug("set is empty: " + iFace.getAccessSet());
761
            iFace.removeAccessSet();
762
            iFace.setAccessSet("none");
763
        }
764
        return iFace;
765
    }
766

    
767
    @Override
768
    public List<String> getDnetCountries() {
769
        LOGGER.debug("Getting dnet-countries!");
770
        return Converter.readFile("countries.txt");
771
    }
772

    
773
    @Override
774
    public List<String> getTypologies() {
775
        return Converter.readFile("typologies.txt");
776
    }
777

    
778
    @Override
779
    public List<Timezone> getTimezones() {
780
        List<String> timezones = Converter.readFile("timezones.txt");
781
        return Converter.toTimezones(timezones);
782
    }
783

    
784
    @Override
785
    public List<String> getUrlsOfUserRepos(String userEmail,
786
                                           String page,
787
                                           String size) {
788
        UriComponents uriComponents = UriComponentsBuilder
789
                .fromHttpUrl(baseAddress + "/api/baseurl/")
790
                .path("/{page}/{size}")
791
                .build().expand(page, size).encode();
792

    
793
        RequestFilter requestFilter = new RequestFilter();
794
        requestFilter.setRegisteredby(userEmail);
795
        return Arrays.asList(restTemplate.postForObject(uriComponents.toUri(), requestFilter, String[].class));
796
    }
797

    
798
    @Override
799
    public List<String> getDatasourceVocabularies(String mode) {
800

    
801
        List<String> resultSet = new ArrayList<>();
802
        for (Map.Entry<String, String> entry : this.getVocabulary("dnet:datasource_typologies").getAsMap().entrySet()) {
803
            if (mode.equalsIgnoreCase("aggregator")) {
804
                if (entry.getKey().contains("aggregator"))
805
                    resultSet.add(entry.getValue());
806
            } else if (mode.equalsIgnoreCase("journal")) {
807
                if (entry.getKey().contains("journal"))
808
                    resultSet.add(entry.getValue());
809
            } else if (mode.equalsIgnoreCase("opendoar")) {
810
                if (entry.getKey().contains("pubsrepository"))
811
                    resultSet.add(entry.getValue());
812
            } else if (mode.equalsIgnoreCase("re3data")) {
813
                if (entry.getKey().contains("datarepository"))
814
                    resultSet.add(entry.getValue());
815
            } else if (mode.equalsIgnoreCase("cris")) {
816
                if (entry.getKey().contains("crissystem"))
817
                    resultSet.add(entry.getValue());
818
            }
819
        }
820

    
821

    
822
        return resultSet;
823
    }
824

    
825
    private Vocabulary getVocabulary(String vocName) {
826

    
827
        if (!vocabularyMap.containsKey(vocName)) {
828
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
829
        }
830
        return vocabularyMap.get(vocName);
831
    }
832

    
833

    
834
    @Override
835
    public Map<String, String> getCompatibilityClasses(String mode) {
836

    
837
        LOGGER.debug("Getting compatibility classes for mode: " + mode);
838
        Map<String, String> retMap = new HashMap<String, String>();
839

    
840
        Map<String, String> compatibilityClasses = this.getVocabulary("dnet:compatibilityLevel").getAsMap();
841
        boolean foundData = false;
842
        for (Map.Entry<String, String> entry : compatibilityClasses.entrySet()) {
843
            if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_ALL))
844
                return compatibilityClasses;
845
            else if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_RE3DATA)) {
846
                if (entry.getKey().matches("^openaire[1-9].0_data$")) {
847
                    retMap.put(entry.getKey(), entry.getValue());
848
                    foundData = true;
849
                }
850
            }
851
            else if (mode.equalsIgnoreCase("cris")) {
852
                if (entry.getKey().contains("openaire-cris")) {
853
                    retMap.put(entry.getKey(), entry.getValue());
854
                    foundData = true;
855
                }
856
            } else {
857
                if (entry.getKey().matches("^openaire[1-9].0$") || entry.getKey().equals("driver"))
858
                    retMap.put(entry.getKey(), entry.getValue());
859
            }
860
        }
861

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

    
866
        return retMap;
867
    }
868

    
869
    @Override
870
    public Map<String, String> getDatasourceClasses(String mode) {
871

    
872
        LOGGER.debug("Getting datasource classes for mode: " + mode);
873

    
874
        Map<String, String> retMap = new HashMap<String, String>();
875

    
876
        for (Map.Entry<String, String> entry : this.getVocabulary("dnet:datasource_typologies").getAsMap().entrySet()) {
877
            if (mode.equalsIgnoreCase("aggregator")) {
878
                if (entry.getKey().contains("aggregator"))
879
                    retMap.put(entry.getKey(), entry.getValue());
880
            } else if (mode.equalsIgnoreCase("journal")) {
881
                if (entry.getKey().contains("journal"))
882
                    retMap.put(entry.getKey(), entry.getValue());
883
            } else if (mode.equalsIgnoreCase("opendoar")) {
884
                if (entry.getKey().contains("pubsrepository"))
885
                    retMap.put(entry.getKey(), entry.getValue());
886
            } else if (mode.equalsIgnoreCase("re3data")) {
887
                if (entry.getKey().contains("datarepository"))
888
                    retMap.put(entry.getKey(), entry.getValue());
889
            } else if (mode.equalsIgnoreCase("cris")) {
890
                if (entry.getKey().contains("crissystem"))
891
                    retMap.put(entry.getKey(), entry.getValue());
892
            }
893
        }
894
        return filterResults(retMap, mode);
895

    
896
    }
897

    
898
    private Map<String, String> filterResults(Map<String, String> map, String mode) {
899

    
900
        HashMap<String, String> filteredMap = new HashMap<>();
901
        for (String key : map.keySet())
902
            if (dataSourceClass.get(mode).contains(key))
903
                filteredMap.put(key, map.get(key));
904

    
905
        return filteredMap;
906
    }
907

    
908
    @Override
909
    public String getCountryName(String countryCode) {
910
        return inverseCountriesMap.get(countryCode);
911
    }
912

    
913
    @Override
914
    public MetricsInfo getMetricsInfoForRepository(String repoId) throws RepositoryServiceException {
915
        try {
916

    
917
            MetricsInfo metricsInfo = new MetricsInfo();
918
            metricsInfo.setDiagramsBaseURL(this.usageStatisticsDiagramsBaseURL);
919
            metricsInfo.setMetricsNumbers(getMetricsNumbers(getOpenAIREId(repoId)));
920
            return metricsInfo;
921

    
922
        } catch (Exception e) {
923
            LOGGER.error("Error while getting metrics info for repository: ", e);
924
            throw new RepositoryServiceException("General error", RepositoryServiceException.ErrorCode.GENERAL_ERROR);
925
        }
926
    }
927

    
928
    @Override
929
    public Map<String, String> getListLatestUpdate(String mode) throws JSONException {
930
        if (mode.equals("opendoar"))
931
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(0).getLastCollectionDate());
932
        else if (mode.equals("cris"))
933
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("eurocrisdris::dris").get(0).getLastCollectionDate());
934
        else
935
            /*
936
             * first api of re3data has null value on collection date
937
             * */
938
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(1).getLastCollectionDate());
939
    }
940

    
941
    private void updateValidationSet(String repositoryId, String repositoryInterfaceId, String validationSet) throws Exception {
942
        UriComponents uriComponents = UriComponentsBuilder
943
                .fromHttpUrl(baseAddress + "/ds/api/oaiset")
944
                .queryParam("dsId", repositoryId)
945
                .queryParam("apiId", repositoryInterfaceId)
946
                .queryParam("oaiSet", validationSet)
947
                .build().encode();
948
        restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, null, ResponseEntity.class);
949

    
950
    }
951

    
952

    
953
    private void updateBaseUrl(String repositoryId, String repositoryInterfaceId, String baseUrl) {
954
        UriComponents uriComponents = UriComponentsBuilder
955
                .fromHttpUrl(baseAddress + "/ds/api/baseurl")
956
                .queryParam("dsId", repositoryId)
957
                .queryParam("apiId", repositoryInterfaceId)
958
                .queryParam("baseUrl", baseUrl)
959
                .build().encode();
960
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
961
    }
962

    
963
    private void updateCompliance(String repositoryId, String repositoryInterfaceId, String compliance) {
964
        UriComponents uriComponents = UriComponentsBuilder
965
                .fromHttpUrl(baseAddress + "/ds/api/compliance")
966
                .queryParam("dsId", repositoryId)
967
                .queryParam("apiId", repositoryInterfaceId)
968
                .queryParam("compliance", compliance)
969
                .build().encode();
970
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
971
    }
972

    
973
    private MetricsNumbers getMetricsNumbers(String openAIREID) throws BrokerException {
974

    
975
        //build the uri params
976
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(this.usageStatisticsNumbersBaseURL + openAIREID + "/clicks");
977

    
978
        //create new template engine
979
        RestTemplate template = new RestTemplate();
980
        template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
981
        ResponseEntity<MetricsNumbers> resp;
982

    
983
        //communicate with endpoint
984
        resp = template.exchange(
985
                builder.build().encode().toUri(),
986
                HttpMethod.GET,
987
                null,
988
                new ParameterizedTypeReference<MetricsNumbers>() {
989
                });
990

    
991
        return resp.getBody();
992
    }
993

    
994
    private String getOpenAIREId(String repoId) {
995

    
996
        if (repoId != null && repoId.contains("::")) {
997
            return repoId.split("::")[0] + "::" + DigestUtils.md5Hex(repoId.split("::")[1]);
998
        }
999

    
1000
        return null;
1001
    }
1002

    
1003
    private UriComponents searchDatasource(String page, String size) {
1004

    
1005
        return UriComponentsBuilder
1006
                .fromHttpUrl(baseAddress + "/ds/searchdetails/")
1007
                .path("/{page}/{size}/")
1008
                .queryParam("requestSortBy", "officialname")
1009
                .queryParam("order", "ASCENDING")
1010
                .build().expand(page, size).encode();
1011
    }
1012

    
1013
    private UriComponents searchSnipperDatasource(String page, String size) {
1014

    
1015
        return UriComponentsBuilder
1016
                .fromHttpUrl(baseAddress + "/ds/searchsnippet/")
1017
                .path("/{page}/{size}/")
1018
                .queryParam("requestSortBy", "officialname")
1019
                .queryParam("order", "ASCENDING")
1020
                .build().expand(page, size).encode();
1021
    }
1022

    
1023
    private UriComponents searchRegisteredDatasource(String requestSortBy, String order, String page, String size) {
1024

    
1025
        return UriComponentsBuilder
1026
                .fromHttpUrl(baseAddress + "/ds/searchregistered/")
1027
                .path("/{page}/{size}/")
1028
                .queryParam("requestSortBy", requestSortBy)
1029
                .queryParam("order", order)
1030
                .build().expand(page, size).encode();
1031
    }
1032

    
1033
    private String getRepositoryType(String typology) {
1034
        return invertedDataSourceClass.get(typology);
1035
    }
1036

    
1037
    private List<String> getRoleIdsFromUserRoles(String userEmail) {
1038
        Integer coPersonId = registryCalls.getCoPersonIdByEmail(userEmail);
1039
        JsonArray roles;
1040
        ArrayList<String> roleIds = new ArrayList<>();
1041
        ArrayList<Integer> couIds = new ArrayList<>();
1042
        if (coPersonId != null) {
1043
            roles = registryCalls.getRolesWithStatus(coPersonId, AaiRegistryService.RoleStatus.ACTIVE);
1044
            for (JsonElement role : roles) {
1045
                JsonObject object = role.getAsJsonObject();
1046
                if (object.get("CouId") == null) {
1047
                    continue;
1048
                }
1049
                couIds.add(object.get("CouId").getAsInt());
1050
            }
1051

    
1052
            roleIds.addAll(registryCalls.getCouNames(couIds).values());
1053

    
1054
        }
1055
        return roleIds;
1056
    }
1057
}
(12-12/20)