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("${api.baseAddress}")
64
    private String baseAddress;
65

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

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

    
72
    @Value("${services.repomanager.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
        dataSourceClass.put("opendoar", Arrays.asList("pubsrepository::institutional", "pubsrepository::thematic", "pubsrepository::unknown", "pubsrepository::mock"));
120
        dataSourceClass.put("re3data", Collections.singletonList("datarepository::unknown"));
121
        dataSourceClass.put("journal", Collections.singletonList("pubsrepository::journal"));
122
        dataSourceClass.put("aggregator", Arrays.asList("aggregator::pubsrepository::institutional", "aggregator::pubsrepository::journals", "aggregator::datarepository", "aggregator::pubsrepository::unknown"));
123

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

    
135

    
136
        httpHeaders = new HttpHeaders();
137
        httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
138

    
139
        for (String vocName : vocabularyNames) {
140
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
141
        }
142

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

    
149

    
150
    }
151

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

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

    
178
        for (String repoId : ids) {
179
            requestFilter.setId(repoId);
180
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
181

    
182
            repos.addAll(Converter.jsonToRepositoryList(new JSONObject(rs)));
183
        }
184

    
185
        for (Repository r : repos)
186
            r.setPiwikInfo(piWikService.getPiwikSiteForRepo(r.getId()));
187
        return repos;
188
    }
189

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

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

    
206
        // here page should be 0
207
        UriComponents uriComponents = searchSnipperDatasource(Integer.toString(Math.abs(page)), Integer.toString(Math.abs(size)));
208
        RequestFilter requestFilter = new RequestFilter();
209

    
210
        try {
211
            for (String repoId : ids) {
212
                requestFilter.setId(repoId);
213

    
214
                String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
215
                JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
216
                resultSet.addAll(mapper.readValue(String.valueOf(jsonArray),
217
                        mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
218
            }
219
        } catch (Exception e) {
220
            LOGGER.debug("Exception on getRepositoriesSnippetOfUser", e);
221
            throw e;
222
        }
223

    
224
        LOGGER.debug("resultSet:" + resultSet);
225
        resultSet.parallelStream().forEach(repositorySnippet -> {
226
            repositorySnippet.setPiwikInfo(piWikService.getPiwikSiteForRepo(repositorySnippet.getId()));
227
        });
228
        return resultSet;
229
    }
230

    
231

    
232
    @Override
233
    public List<RepositorySnippet> getRepositoriesByCountry(String country,
234
                                                            String mode,
235
                                                            Boolean managed) throws JSONException, IOException {
236

    
237
        LOGGER.debug("Getting repositories by country!");
238
        int page = 0;
239
        int size = 100;
240
        List<RepositorySnippet> resultSet = new ArrayList<>();
241
        ObjectMapper mapper = new ObjectMapper();
242

    
243
        String filterKey = "UNKNOWN";
244
        if (mode.equalsIgnoreCase("opendoar"))
245
            filterKey = "openaire____::opendoar";
246
        else if (mode.equalsIgnoreCase("re3data"))
247
            filterKey = "openaire____::re3data";
248

    
249

    
250
        LOGGER.debug("Country code equals : " + country);
251
        LOGGER.debug("Filter mode equals : " + filterKey);
252

    
253
        UriComponents uriComponents = searchSnipperDatasource(String.valueOf(page), String.valueOf(size));
254
        RequestFilter requestFilter = new RequestFilter();
255
        requestFilter.setCountry(country);
256
        requestFilter.setCollectedfrom(filterKey);
257

    
258
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
259
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
260
        while (jsonArray.length() > 0) {
261

    
262
LOGGER.debug("json: " + jsonArray);
263

    
264
            resultSet.addAll(mapper.readValue(String.valueOf(jsonArray),
265
                    mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
266
            page += 1;
267
            uriComponents = searchSnipperDatasource(String.valueOf(page), String.valueOf(size));
268
            rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
269
            jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
270
        }
271
        return resultSet;
272
    }
273

    
274
    public List<RepositorySnippet> searchRegisteredRepositories(String country, String typology, String englishName,
275
                                                                String officialName, String requestSortBy, String order, int page, int pageSize) throws Exception {
276

    
277
        LOGGER.debug("Searching registered repositories");
278

    
279
        List<RepositorySnippet> resultSet = new ArrayList<>();
280
        ObjectMapper mapper = new ObjectMapper();
281

    
282
        UriComponents uriComponents = searchRegisteredDatasource(requestSortBy, order, Integer.toString(page), Integer.toString(pageSize));
283

    
284
        RequestFilter requestFilter = new RequestFilter();
285
        requestFilter.setCountry(country);
286
        requestFilter.setTypology(typology);
287
        requestFilter.setOfficialname(officialName);
288
        requestFilter.setEnglishname(englishName);
289

    
290
        try {
291
            String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
292
            JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
293

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

    
296
            return resultSet;
297
        } catch (Exception e) {
298
            LOGGER.error("Error searching registered datasources", e);
299
            throw e;
300
        }
301
    }
302

    
303
    private Repository updateRepositoryInfo(Repository r) throws JSONException {
304

    
305
        /*
306
         * from datasource class
307
         * we get the datasource type form the inverted map
308
         * */
309
        r.setDatasourceType(getRepositoryType(r.getDatasourceClass()));
310
        r.setInterfaces(this.getRepositoryInterface(r.getId()));
311
        r.setPiwikInfo(piWikService.getPiwikSiteForRepo(r.getId()));
312
        r.setCountryName(getCountryName(r.getCountryCode()));
313
        return r;
314
    }
315

    
316

    
317
    private Collection<Repository> getRepositoriesByMode(String mode, List<Repository> rs) {
318

    
319
        List<Repository> reps = new ArrayList<>();
320
        for (Repository r : rs) {
321
            if (r.getCollectedFrom() != null && r.getCollectedFrom().equals(mode))
322
                reps.add(r);
323

    
324
        }
325
        return reps;
326
    }
327

    
328
    @Override
329
    public List<Repository> getRepositoriesOfUser(String page, String size) throws JSONException {
330
        String userEmail = ((OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication()).getUserInfo().getEmail();
331
        LOGGER.debug("Retreiving repositories of authenticated user : " + userEmail);
332
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles());
333
        return getRepositories(new ArrayList<>(repoIds));
334
    }
335

    
336
    @Override
337
    public List<Repository> getRepositoriesOfUser(String userEmail, String page, String size) throws JSONException {
338
        LOGGER.debug("Retreiving repositories of authenticated user : " + userEmail);
339
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles(userEmail));
340
        return getRepositories(new ArrayList<>(repoIds));
341
    }
342

    
343
    @Override
344
    public List<RepositorySnippet> getRepositoriesSnippetsOfUser(String page, String size) throws Exception {
345
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles());
346
        return getRepositoriesSnippets(new ArrayList<>(repoIds));
347
    }
348

    
349
    @Override
350
    public List<RepositorySnippet> getRepositoriesSnippetsOfUser(String userEmail, String page, String size) throws Exception {
351
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles(userEmail));
352
        return getRepositoriesSnippets(new ArrayList<>(repoIds));
353
    }
354

    
355
    @Override
356
    public RepositorySnippet getRepositorySnippetById(String id) throws JSONException, ResourceNotFoundException {
357

    
358
        LOGGER.debug("Retreiving repositories with id : " + id);
359
        RepositorySnippet repo = null;
360
        UriComponents uriComponents = searchSnipperDatasource("0", "100");
361
        RequestFilter requestFilter = new RequestFilter();
362
        requestFilter.setId(id);
363

    
364
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
365
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
366

    
367
        if (jsonArray.length() == 0)
368
            throw new ResourceNotFoundException();
369

    
370
        repo = Converter.jsonToRepositorySnippetObject(jsonArray.getJSONObject(0));
371
        return repo;
372
    }
373

    
374
    @Override
375
    public Repository getRepositoryById(String id) throws JSONException, ResourceNotFoundException {
376

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

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

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

    
389
        repo = Converter.jsonToRepositoryObject(jsonArray.getJSONObject(0));
390
        return updateRepositoryInfo(repo);
391
    }
392

    
393

    
394
    @Override
395
    public List<AggregationDetails> getRepositoryAggregations(String id, int from, int size) throws JSONException {
396

    
397
        LOGGER.debug("Retreiving aggregations for repository with id : " + id);
398
        UriComponents uriComponents = searchDatasource(from + "", size + "");
399
        RequestFilter requestFilter = new RequestFilter();
400
        requestFilter.setId(id);
401

    
402
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
403

    
404
        long start = System.currentTimeMillis();
405
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
406
        long end = System.currentTimeMillis();
407

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

    
411
        if (repository.getJSONArray("datasourceInfo").length() == 0)
412
            return aggregationHistory;
413

    
414
        start = System.currentTimeMillis();
415
        aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
416
        end = System.currentTimeMillis();
417

    
418
        System.out.println("Getting aggregations history from json " + (end - start) + "ms");
419
        return aggregationHistory.size() == 0 ? aggregationHistory : aggregationHistory.stream()
420
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
421
                .limit(size)
422
                .collect(Collectors.toList());
423

    
424
    }
425

    
426
    @Override
427
    public Map<String, List<AggregationDetails>> getRepositoryAggregationsByYear(String id) throws JSONException {
428
        LOGGER.debug("Retreiving aggregations (by year) for repository with id : " + id);
429
        UriComponents uriComponents = searchDatasource("0", "100");
430
        RequestFilter requestFilter = new RequestFilter();
431
        requestFilter.setId(id);
432

    
433
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
434
        Map<String, List<AggregationDetails>> aggregationByYear = new HashMap<>();
435

    
436
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
437
        JSONObject repository = new JSONObject(rs);
438

    
439
        if (repository.getJSONArray("datasourceInfo").length() == 0)
440
            return aggregationByYear;
441

    
442
        aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
443
        return aggregationHistory.size() == 0 ? aggregationByYear : createYearMap(aggregationHistory);
444
    }
445

    
446
    private Map<String, List<AggregationDetails>> createYearMap(List<AggregationDetails> aggregationHistory) {
447
        Map<String, List<AggregationDetails>> aggregationByYear;
448
        aggregationHistory = aggregationHistory.stream()
449
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
450
                .collect(Collectors.toList());
451

    
452
        return aggregationHistory.stream()
453
                .collect(Collectors.groupingBy(AggregationDetails::getYear));
454
    }
455

    
456

    
457
    @Override
458
    public List<Repository> getRepositoriesByName(String name,
459
                                                  String page,
460
                                                  String size) throws JSONException {
461

    
462
        LOGGER.debug("Retreiving  repositories with official name : " + name);
463
        UriComponents uriComponents = searchDatasource("0", "100");
464
        RequestFilter requestFilter = new RequestFilter();
465
        requestFilter.setOfficialname(name);
466

    
467
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
468
        List<Repository> repos = Converter.jsonToRepositoryList(new JSONObject(rs));
469
        for (Repository r : repos)
470
            updateRepositoryInfo(r);
471
        return repos;
472

    
473
    }
474

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

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

    
483
        String rs = restTemplate.getForObject(uriComponents.toUri(), String.class);
484
        return Converter.jsonToRepositoryInterfaceList(new JSONObject(rs));
485

    
486
    }
487

    
488
    @Override
489
    public Repository addRepository(String datatype, Repository repository) throws Exception {
490

    
491
        LOGGER.debug("storing " + datatype + " repository with id: " + repository.getId());
492

    
493
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
494
        repository.setActivationId(UUID.randomUUID().toString());
495
        repository.setCollectedFrom("infrastruct_::openaire");
496

    
497
        if (datatype.equals("journal")) {
498
            repository.setId("openaire____::issn" + repository.getIssn());
499
            repository.setNamespacePrefix("issn" + repository.getIssn());
500
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
501
        } else if (datatype.equals("aggregator")) {
502
            repository.setId("openaire____::" + DigestUtils.md5Hex(repository.getOfficialName()));
503
            repository.setNamespacePrefix(DigestUtils.md5Hex(repository.getOfficialName()).substring(0, 12));
504
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
505
        } else {
506
            this.latentUpdate(repository, SecurityContextHolder.getContext().getAuthentication());
507
        }
508

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

    
526
        // Assign new role to the user that created it
527
        Integer coPersonId = registryCalls.getCoPersonIdByIdentifier();
528
        if (couId != null) {
529
            Integer role = registryCalls.getRoleId(coPersonId, couId);
530
            try {
531
                registryCalls.assignMemberRole(coPersonId, couId, role);
532

    
533
                // Add role to current user authorities
534
                authoritiesUpdater.addRole(roleMappingService.convertRepoIdToAuthority(repository.getId()));
535
            } catch (Exception e) {
536
                LOGGER.debug("Exception on assign role to user during add repository", e);
537
                throw e;
538
            }
539

    
540
        }
541

    
542

    
543
        return repository;
544
    }
545

    
546
    /* update method acting as add -> send email with registration topic/body*/
547
    private Repository latentUpdate(Repository repository, Authentication authentication) throws Exception {
548
        UriComponents uriComponents = UriComponentsBuilder
549
                .fromHttpUrl(baseAddress + "/ds/update/")
550
                .build()
551
                .encode();
552

    
553
        String json_repository = Converter.repositoryObjectToJson(repository);
554
        LOGGER.debug("JSON to add(update) -> " + json_repository);
555

    
556
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
557
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
558

    
559
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
560
            try {
561
                emailUtils.sendUserRegistrationEmail(repository, authentication);
562
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
563
            } catch (Exception e) {
564
                LOGGER.error("Error sending email", e);
565
            }
566
        } else
567
            LOGGER.error("Error storing repository: " + responseEntity.getBody().toString());
568

    
569
        return repository;
570
    }
571

    
572
    @Override
573
    public Repository updateRepository(Repository repository, Authentication authentication) throws Exception {
574
        UriComponents uriComponents = UriComponentsBuilder
575
                .fromHttpUrl(baseAddress + "/ds/update/")
576
                .build()
577
                .encode();
578

    
579
        String json_repository = Converter.repositoryObjectToJson(repository);
580

    
581
        LOGGER.debug("JSON to update -> " + json_repository);
582

    
583
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
584
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity
585
                , ResponseEntity.class);
586

    
587
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
588
            try {
589
                emailUtils.sendUserUpdateRepositoryInfoEmail(repository, authentication);
590
                emailUtils.sendAdminUpdateRepositoryInfoEmail(repository, authentication);
591
            } catch (Exception e) {
592
                LOGGER.error("Error sending emails: " + e);
593
            }
594
        } else
595
            LOGGER.debug(responseEntity.getBody().toString());
596

    
597
        return repository;
598
    }
599

    
600
    private void storeRepository(Repository repository, Authentication authentication) throws Exception {
601

    
602
        Date utilDate = new Date();
603
        Timestamp date = new Timestamp(utilDate.getTime());
604
        repository.setDateOfCollection(date);
605
        repository.setAggregator("OPENAIRE");
606
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
607

    
608
        UriComponents uriComponents = UriComponentsBuilder
609
                .fromHttpUrl(baseAddress + "/ds/add/")
610
                .build()
611
                .encode();
612
        String json_repository = Converter.repositoryObjectToJson(repository);
613
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
614
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
615

    
616
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
617
            try {
618
                emailUtils.sendUserRegistrationEmail(repository, authentication);
619
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
620
            } catch (Exception e) {
621
                LOGGER.error("Error sending emails: " + e);
622
            }
623
        } else {
624
            LOGGER.debug(responseEntity.getBody().toString());
625
        }
626
    }
627

    
628
    @Override
629
    public void deleteRepositoryInterface(String id,
630
                                          String registeredBy) {
631
        UriComponents uriComponents = UriComponentsBuilder
632
                .fromHttpUrl(baseAddress + "/ds/api/")
633
                .path("/{id}")
634
                .build().expand(id).encode();
635
        LOGGER.debug(uriComponents.toUri());
636
        restTemplate.delete(uriComponents.toUri());
637
    }
638

    
639
    @Override
640
    public RepositoryInterface addRepositoryInterface(String datatype,
641
                                                      String repoId,
642
                                                      String registeredBy,
643
                                                      String comment, RepositoryInterface repositoryInterface) throws Exception {
644
        Repository e = this.getRepositoryById(repoId);
645
        repositoryInterface = createRepositoryInterface(e, repositoryInterface, datatype);
646
        String json_interface = Converter.repositoryInterfaceObjectToJson(e, repositoryInterface);
647

    
648
        UriComponents uriComponents = UriComponentsBuilder
649
                .fromHttpUrl(baseAddress + "/ds/api/add/")
650
                .build()
651
                .encode();
652

    
653
        HttpEntity<String> httpEntity = new HttpEntity<>(json_interface, httpHeaders);
654

    
655
        restTemplate.postForObject(uriComponents.toUri(), httpEntity, String.class);
656

    
657
        try {
658
            emailUtils.sendAdminRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
659
            emailUtils.sendUserRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
660
        } catch (Exception ex) {
661
            LOGGER.error("Error sending emails: " + ex);
662
        }
663

    
664
        submitInterfaceValidation(e, registeredBy, repositoryInterface, false);
665

    
666
        return repositoryInterface;
667
    }
668

    
669
    @Override
670
    public RepositoryInterface updateRepositoryInterface(String repoId,
671
                                                         String registeredBy,
672
                                                         String comment, RepositoryInterface repositoryInterface) throws Exception {
673

    
674
        this.updateBaseUrl(repoId, repositoryInterface.getId(), repositoryInterface.getBaseUrl());
675
        this.updateCompliance(repoId, repositoryInterface.getId(), repositoryInterface.getCompliance());
676
        this.updateValidationSet(repoId, repositoryInterface.getId(), repositoryInterface.getAccessSet());
677

    
678
        Repository repository = this.getRepositoryById(repoId);
679
        try {
680
            try {
681
                emailUtils.sendAdminUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
682
                emailUtils.sendUserUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
683
            } catch (Exception e) {
684
                LOGGER.error("Error sending emails: " + e);
685
            }
686
        } catch (Exception e) {
687
            LOGGER.warn("Could not send emails", e);
688
        }
689

    
690
        submitInterfaceValidation(getRepositoryById(repoId), registeredBy, repositoryInterface, true);
691

    
692
        return repositoryInterface;
693
    }
694

    
695
    private void submitInterfaceValidation(Repository repo, String userEmail, RepositoryInterface iFace, boolean updateExisting) throws ValidatorServiceException {
696
        JobForValidation job = new JobForValidation();
697

    
698
        job.setActivationId(UUID.randomUUID().toString());
699
        job.setAdminEmails(Collections.singletonList(this.adminEmail));
700
        job.setBaseUrl(iFace.getBaseUrl());
701
        job.setDatasourceId(repo.getId());
702
        job.setDesiredCompatibilityLevel(iFace.getDesiredCompatibilityLevel());
703
        job.setInterfaceId(iFace.getId());
704
        job.setOfficialName(repo.getOfficialName());
705
        job.setRepoType(repo.getDatasourceType());
706
        job.setUserEmail(userEmail);
707
        job.setValidationSet((iFace.getAccessSet().isEmpty() ? "none" : iFace.getAccessSet()));
708
        job.setRecords(-1);
709
        job.setRegistration(!updateExisting);
710
        job.setUpdateExisting(updateExisting);
711

    
712
        this.validatorService.submitJobForValidation(job);
713
    }
714

    
715
    private RepositoryInterface createRepositoryInterface(Repository repo, RepositoryInterface iFace, String datatype) {
716

    
717
        iFace.setContentDescription("metadata");
718
        iFace.setCompliance("UNKNOWN");
719

    
720
        if (datatype.equals("re3data"))
721
            iFace.setAccessFormat("oai_datacite");
722
        else
723
            iFace.setAccessFormat("oai_dc");
724

    
725

    
726
        if (repo.getDatasourceClass() != null && !repo.getDatasourceClass().isEmpty())
727
            iFace.setTypology(repo.getDatasourceClass());
728
        else if (datatype.equalsIgnoreCase("journal"))
729
            iFace.setTypology("pubsrepository::journal");
730
        else if (datatype.equalsIgnoreCase("aggregator"))
731
            iFace.setTypology("aggregator::pubsrepository::unknown");
732
        else if (datatype.equalsIgnoreCase("opendoar"))
733
            iFace.setTypology("pubsrepository::unknown");
734
        else if (datatype.equalsIgnoreCase("re3data"))
735
            iFace.setTypology("datarepository::unknown");
736

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

    
749
    @Override
750
    public List<String> getDnetCountries() {
751
        LOGGER.debug("Getting dnet-countries!");
752
        return Converter.readFile("countries.txt");
753
    }
754

    
755
    @Override
756
    public List<String> getTypologies() {
757
        return Converter.readFile("typologies.txt");
758
    }
759

    
760
    @Override
761
    public List<Timezone> getTimezones() {
762
        List<String> timezones = Converter.readFile("timezones.txt");
763
        return Converter.toTimezones(timezones);
764
    }
765

    
766
    @Override
767
    public List<String> getUrlsOfUserRepos(String userEmail,
768
                                           String page,
769
                                           String size) {
770
        UriComponents uriComponents = UriComponentsBuilder
771
                .fromHttpUrl(baseAddress + "/api/baseurl/")
772
                .path("/{page}/{size}")
773
                .build().expand(page, size).encode();
774

    
775
        RequestFilter requestFilter = new RequestFilter();
776
        requestFilter.setRegisteredby(userEmail);
777
        return Arrays.asList(restTemplate.postForObject(uriComponents.toUri(), requestFilter, String[].class));
778
    }
779

    
780
    @Override
781
    public List<String> getDatasourceVocabularies(String mode) {
782

    
783
        List<String> resultSet = new ArrayList<>();
784
        for (Map.Entry<String, String> entry : this.getVocabulary("dnet:datasource_typologies").getAsMap().entrySet()) {
785
            if (mode.equalsIgnoreCase("aggregator")) {
786
                if (entry.getKey().contains("aggregator"))
787
                    resultSet.add(entry.getValue());
788
            } else if (mode.equalsIgnoreCase("journal")) {
789
                if (entry.getKey().contains("journal"))
790
                    resultSet.add(entry.getValue());
791
            } else if (mode.equalsIgnoreCase("opendoar")) {
792
                if (entry.getKey().contains("pubsrepository"))
793
                    resultSet.add(entry.getValue());
794
            } else if (mode.equalsIgnoreCase("re3data")) {
795
                if (entry.getKey().contains("datarepository"))
796
                    resultSet.add(entry.getValue());
797
            }
798
        }
799

    
800

    
801
        return resultSet;
802
    }
803

    
804
    private Vocabulary getVocabulary(String vocName) {
805

    
806
        if (!vocabularyMap.containsKey(vocName)) {
807
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
808
        }
809
        return vocabularyMap.get(vocName);
810
    }
811

    
812

    
813
    @Override
814
    public Map<String, String> getCompatibilityClasses(String mode) {
815

    
816
        LOGGER.debug("Getting compatibility classes for mode: " + mode);
817
        Map<String, String> retMap = new HashMap<String, String>();
818

    
819
        Map<String, String> compatibilityClasses = this.getVocabulary("dnet:compatibilityLevel").getAsMap();
820
        boolean foundData = false;
821
        for (Map.Entry<String, String> entry : compatibilityClasses.entrySet()) {
822
            if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_ALL))
823
                return compatibilityClasses;
824
            else if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_RE3DATA)) {
825
                if (entry.getKey().matches("^openaire[1-9].0_data$")) {
826
                    retMap.put(entry.getKey(), entry.getValue());
827
                    foundData = true;
828
                }
829
            } else {
830
                if (entry.getKey().matches("^openaire[1-9].0$") || entry.getKey().equals("driver"))
831
                    retMap.put(entry.getKey(), entry.getValue());
832
            }
833
        }
834

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

    
839
        return retMap;
840
    }
841

    
842
    @Override
843
    public Map<String, String> getDatasourceClasses(String mode) {
844

    
845
        LOGGER.debug("Getting datasource classes for mode: " + mode);
846

    
847
        Map<String, String> retMap = new HashMap<String, String>();
848

    
849
        for (Map.Entry<String, String> entry : this.getVocabulary("dnet:datasource_typologies").getAsMap().entrySet()) {
850
            if (mode.equalsIgnoreCase("aggregator")) {
851
                if (entry.getKey().contains("aggregator"))
852
                    retMap.put(entry.getKey(), entry.getValue());
853
            } else if (mode.equalsIgnoreCase("journal")) {
854
                if (entry.getKey().contains("journal"))
855
                    retMap.put(entry.getKey(), entry.getValue());
856
            } else if (mode.equalsIgnoreCase("opendoar")) {
857
                if (entry.getKey().contains("pubsrepository"))
858
                    retMap.put(entry.getKey(), entry.getValue());
859
            } else if (mode.equalsIgnoreCase("re3data")) {
860
                if (entry.getKey().contains("datarepository"))
861
                    retMap.put(entry.getKey(), entry.getValue());
862
            }
863
        }
864
        return filterResults(retMap, mode);
865

    
866
    }
867

    
868
    private Map<String, String> filterResults(Map<String, String> map, String mode) {
869

    
870
        HashMap<String, String> filteredMap = new HashMap<>();
871
        for (String key : map.keySet())
872
            if (dataSourceClass.get(mode).contains(key))
873
                filteredMap.put(key, map.get(key));
874

    
875
        return filteredMap;
876
    }
877

    
878
    @Override
879
    public String getCountryName(String countryCode) {
880
        return inverseCountriesMap.get(countryCode);
881
    }
882

    
883
    @Override
884
    public MetricsInfo getMetricsInfoForRepository(String repoId) throws RepositoryServiceException {
885
        try {
886

    
887
            MetricsInfo metricsInfo = new MetricsInfo();
888
            metricsInfo.setDiagramsBaseURL(this.usageStatisticsDiagramsBaseURL);
889
            metricsInfo.setMetricsNumbers(getMetricsNumbers(getOpenAIREId(repoId)));
890
            return metricsInfo;
891

    
892
        } catch (Exception e) {
893
            LOGGER.error("Error while getting metrics info for repository: ", e);
894
            throw new RepositoryServiceException("General error", RepositoryServiceException.ErrorCode.GENERAL_ERROR);
895
        }
896
    }
897

    
898
    @Override
899
    public Map<String, String> getListLatestUpdate(String mode) throws JSONException {
900
        if (mode.equals("opendoar"))
901
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(0).getLastCollectionDate());
902
        else
903
            /*
904
             * first api of re3data has null value on collection date
905
             * */
906
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(1).getLastCollectionDate());
907
    }
908

    
909
    private void updateValidationSet(String repositoryId, String repositoryInterfaceId, String validationSet) throws Exception {
910
        UriComponents uriComponents = UriComponentsBuilder
911
                .fromHttpUrl(baseAddress + "/ds/api/oaiset")
912
                .queryParam("dsId", repositoryId)
913
                .queryParam("apiId", repositoryInterfaceId)
914
                .queryParam("oaiSet", validationSet)
915
                .build().encode();
916
        restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, null, ResponseEntity.class);
917

    
918
    }
919

    
920

    
921
    private void updateBaseUrl(String repositoryId, String repositoryInterfaceId, String baseUrl) {
922
        UriComponents uriComponents = UriComponentsBuilder
923
                .fromHttpUrl(baseAddress + "/ds/api/baseurl")
924
                .queryParam("dsId", repositoryId)
925
                .queryParam("apiId", repositoryInterfaceId)
926
                .queryParam("baseUrl", baseUrl)
927
                .build().encode();
928
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
929
    }
930

    
931
    private void updateCompliance(String repositoryId, String repositoryInterfaceId, String compliance) {
932
        UriComponents uriComponents = UriComponentsBuilder
933
                .fromHttpUrl(baseAddress + "/ds/api/compliance")
934
                .queryParam("dsId", repositoryId)
935
                .queryParam("apiId", repositoryInterfaceId)
936
                .queryParam("compliance", compliance)
937
                .build().encode();
938
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
939
    }
940

    
941
    private MetricsNumbers getMetricsNumbers(String openAIREID) throws BrokerException {
942

    
943
        //build the uri params
944
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(this.usageStatisticsNumbersBaseURL + openAIREID + "/clicks");
945

    
946
        //create new template engine
947
        RestTemplate template = new RestTemplate();
948
        template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
949
        ResponseEntity<MetricsNumbers> resp;
950

    
951
        //communicate with endpoint
952
        resp = template.exchange(
953
                builder.build().encode().toUri(),
954
                HttpMethod.GET,
955
                null,
956
                new ParameterizedTypeReference<MetricsNumbers>() {
957
                });
958

    
959
        return resp.getBody();
960
    }
961

    
962
    private String getOpenAIREId(String repoId) {
963

    
964
        if (repoId != null && repoId.contains("::")) {
965
            return repoId.split("::")[0] + "::" + DigestUtils.md5Hex(repoId.split("::")[1]);
966
        }
967

    
968
        return null;
969
    }
970

    
971
    private UriComponents searchDatasource(String page, String size) {
972

    
973
        return UriComponentsBuilder
974
                .fromHttpUrl(baseAddress + "/ds/search/")
975
                .path("/{page}/{size}/")
976
                .queryParam("requestSortBy", "officialname")
977
                .queryParam("order", "ASCENDING")
978
                .build().expand(page, size).encode();
979
    }
980

    
981
    private UriComponents searchSnipperDatasource(String page, String size) {
982

    
983
        return UriComponentsBuilder
984
                .fromHttpUrl(baseAddress + "/ds/searchsnippet/")
985
                .path("/{page}/{size}/")
986
                .queryParam("requestSortBy", "officialname")
987
                .queryParam("order", "ASCENDING")
988
                .build().expand(page, size).encode();
989
    }
990

    
991
    private UriComponents searchRegisteredDatasource(String requestSortBy, String order, String page, String size) {
992

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

    
1001
    private String getRepositoryType(String typology) {
1002
        return invertedDataSourceClass.get(typology);
1003
    }
1004

    
1005
    private List<String> getRoleIdsFromUserRoles(String userEmail) {
1006
        Integer coPersonId = registryCalls.getCoPersonIdByEmail(userEmail);
1007
        JsonArray roles;
1008
        ArrayList<String> roleIds = new ArrayList<>();
1009
        ArrayList<Integer> couIds = new ArrayList<>();
1010
        if (coPersonId != null) {
1011
            roles = registryCalls.getRolesWithStatus(coPersonId, AaiRegistryService.RoleStatus.ACTIVE);
1012
            for (JsonElement role : roles) {
1013
                JsonObject object = role.getAsJsonObject();
1014
                if (object.get("CouId") == null) {
1015
                    continue;
1016
                }
1017
                couIds.add(object.get("CouId").getAsInt());
1018
            }
1019

    
1020
            roleIds.addAll(registryCalls.getCouNames(couIds).values());
1021

    
1022
        }
1023
        return roleIds;
1024
    }
1025
}
(12-12/20)