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
        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
    @Override
304
    public int getTotalRegisteredRepositories() {
305
        UriComponents uriComponents = UriComponentsBuilder
306
                .fromHttpUrl(baseAddress + "/ds/countregistered")
307
                .queryParam("fromDate", "1900-01-01")
308
                .build().encode();
309

    
310
        return restTemplate.getForObject(uriComponents.toUri(), Integer.class);
311
    }
312

    
313
    private Repository updateRepositoryInfo(Repository r) throws JSONException {
314

    
315
        /*
316
         * from datasource class
317
         * we get the datasource type form the inverted map
318
         * */
319
        r.setDatasourceType(getRepositoryType(r.getDatasourceClass()));
320
        r.setInterfaces(this.getRepositoryInterface(r.getId()));
321
        r.setPiwikInfo(piWikService.getPiwikSiteForRepo(r.getId()));
322
        r.setCountryName(getCountryName(r.getCountryCode()));
323
        return r;
324
    }
325

    
326

    
327
    private Collection<Repository> getRepositoriesByMode(String mode, List<Repository> rs) {
328

    
329
        List<Repository> reps = new ArrayList<>();
330
        for (Repository r : rs) {
331
            if (r.getCollectedFrom() != null && r.getCollectedFrom().equals(mode))
332
                reps.add(r);
333

    
334
        }
335
        return reps;
336
    }
337

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

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

    
353
    @Override
354
    public List<RepositorySnippet> getRepositoriesSnippetsOfUser(String page, String size) throws Exception {
355
        Collection<String> repoIds = roleMappingService.getRepoIdsByRoleIds(authorizationService.getUserRoles());
356
        return getRepositoriesSnippets(new ArrayList<>(repoIds));
357
    }
358

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

    
365
    @Override
366
    public RepositorySnippet getRepositorySnippetById(String id) throws JSONException, ResourceNotFoundException {
367

    
368
        LOGGER.debug("Retreiving repositories with id : " + id);
369
        RepositorySnippet repo = null;
370
        UriComponents uriComponents = searchSnipperDatasource("0", "100");
371
        RequestFilter requestFilter = new RequestFilter();
372
        requestFilter.setId(id);
373

    
374
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
375
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
376

    
377
        if (jsonArray.length() == 0)
378
            throw new ResourceNotFoundException();
379

    
380
        repo = Converter.jsonToRepositorySnippetObject(jsonArray.getJSONObject(0));
381
        return repo;
382
    }
383

    
384
    @Override
385
    public Repository getRepositoryById(String id) throws JSONException, ResourceNotFoundException {
386

    
387
        LOGGER.debug("Retreiving repositories with id : " + id);
388
        Repository repo = null;
389
        UriComponents uriComponents = searchDatasource("0", "100");
390
        RequestFilter requestFilter = new RequestFilter();
391
        requestFilter.setId(id);
392

    
393
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
394
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
395

    
396
        if (jsonArray.length() == 0)
397
            throw new ResourceNotFoundException();
398

    
399
        repo = Converter.jsonToRepositoryObject(jsonArray.getJSONObject(0));
400
        return updateRepositoryInfo(repo);
401
    }
402

    
403

    
404
    @Override
405
    public List<AggregationDetails> getRepositoryAggregations(String id, int from, int size) throws JSONException {
406

    
407
        LOGGER.debug("Retreiving aggregations for repository with id : " + id);
408
        UriComponents uriComponents = searchDatasource(from + "", size + "");
409
        RequestFilter requestFilter = new RequestFilter();
410
        requestFilter.setId(id);
411

    
412
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
413

    
414
        long start = System.currentTimeMillis();
415
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
416
        long end = System.currentTimeMillis();
417

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

    
421
        if (repository.getJSONArray("datasourceInfo").length() == 0)
422
            return aggregationHistory;
423

    
424
        start = System.currentTimeMillis();
425
        aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
426
        end = System.currentTimeMillis();
427

    
428
        System.out.println("Getting aggregations history from json " + (end - start) + "ms");
429
        return aggregationHistory.size() == 0 ? aggregationHistory : aggregationHistory.stream()
430
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
431
                .limit(size)
432
                .collect(Collectors.toList());
433

    
434
    }
435

    
436
    @Override
437
    public Map<String, List<AggregationDetails>> getRepositoryAggregationsByYear(String id) throws JSONException {
438
        LOGGER.debug("Retreiving aggregations (by year) for repository with id : " + id);
439
        UriComponents uriComponents = searchDatasource("0", "100");
440
        RequestFilter requestFilter = new RequestFilter();
441
        requestFilter.setId(id);
442

    
443
        List<AggregationDetails> aggregationHistory = new ArrayList<>();
444
        Map<String, List<AggregationDetails>> aggregationByYear = new HashMap<>();
445

    
446
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
447
        JSONObject repository = new JSONObject(rs);
448

    
449
        if (repository.getJSONArray("datasourceInfo").length() == 0)
450
            return aggregationByYear;
451

    
452
        aggregationHistory.addAll(Converter.getAggregationHistoryFromJson(repository.getJSONArray("datasourceInfo").getJSONObject(0)));
453
        return aggregationHistory.size() == 0 ? aggregationByYear : createYearMap(aggregationHistory);
454
    }
455

    
456
    private Map<String, List<AggregationDetails>> createYearMap(List<AggregationDetails> aggregationHistory) {
457
        Map<String, List<AggregationDetails>> aggregationByYear;
458
        aggregationHistory = aggregationHistory.stream()
459
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
460
                .collect(Collectors.toList());
461

    
462
        return aggregationHistory.stream()
463
                .collect(Collectors.groupingBy(AggregationDetails::getYear));
464
    }
465

    
466

    
467
    @Override
468
    public List<Repository> getRepositoriesByName(String name,
469
                                                  String page,
470
                                                  String size) throws JSONException {
471

    
472
        LOGGER.debug("Retreiving  repositories with official name : " + name);
473
        UriComponents uriComponents = searchDatasource("0", "100");
474
        RequestFilter requestFilter = new RequestFilter();
475
        requestFilter.setOfficialname(name);
476

    
477
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
478
        List<Repository> repos = Converter.jsonToRepositoryList(new JSONObject(rs));
479
        for (Repository r : repos)
480
            updateRepositoryInfo(r);
481
        return repos;
482

    
483
    }
484

    
485
    @Override
486
    public List<RepositoryInterface> getRepositoryInterface(String id) throws JSONException {
487

    
488
        UriComponents uriComponents = UriComponentsBuilder
489
                .fromHttpUrl(baseAddress + "/ds/api/")
490
                .path("/{id}")
491
                .build().expand(id).encode();
492

    
493
        String rs = restTemplate.getForObject(uriComponents.toUri(), String.class);
494
        return Converter.jsonToRepositoryInterfaceList(new JSONObject(rs));
495

    
496
    }
497

    
498
    @Override
499
    public Repository addRepository(String datatype, Repository repository) throws Exception {
500

    
501
        LOGGER.debug("storing " + datatype + " repository with id: " + repository.getId());
502

    
503
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
504
        repository.setActivationId(UUID.randomUUID().toString());
505
        repository.setCollectedFrom("infrastruct_::openaire");
506

    
507
        if (datatype.equals("journal")) {
508
            repository.setId("openaire____::issn" + repository.getIssn());
509
            repository.setNamespacePrefix("issn" + repository.getIssn());
510
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
511
        } else if (datatype.equals("aggregator")) {
512
            repository.setId("openaire____::" + DigestUtils.md5Hex(repository.getOfficialName()));
513
            repository.setNamespacePrefix(DigestUtils.md5Hex(repository.getOfficialName()).substring(0, 12));
514
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
515
        } else {
516
            this.latentUpdate(repository, SecurityContextHolder.getContext().getAuthentication());
517
        }
518

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

    
536
        // Assign new role to the user that created it
537
        Integer coPersonId = registryCalls.getCoPersonIdByIdentifier();
538
        if (couId != null) {
539
            Integer role = registryCalls.getRoleId(coPersonId, couId);
540
            try {
541
                registryCalls.assignMemberRole(coPersonId, couId, role);
542

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

    
550
        }
551

    
552

    
553
        return repository;
554
    }
555

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

    
563
        String json_repository = Converter.repositoryObjectToJson(repository);
564
        LOGGER.debug("JSON to add(update) -> " + json_repository);
565

    
566
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
567
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
568

    
569
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
570
            try {
571
                emailUtils.sendUserRegistrationEmail(repository, authentication);
572
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
573
            } catch (Exception e) {
574
                LOGGER.error("Error sending email", e);
575
            }
576
        } else
577
            LOGGER.error("Error storing repository: " + responseEntity.getBody().toString());
578

    
579
        return repository;
580
    }
581

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

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

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

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

    
597
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
598
            try {
599
                emailUtils.sendUserUpdateRepositoryInfoEmail(repository, authentication);
600
                emailUtils.sendAdminUpdateRepositoryInfoEmail(repository, authentication);
601
            } catch (Exception e) {
602
                LOGGER.error("Error sending emails: " + e);
603
            }
604
        } else
605
            LOGGER.debug(responseEntity.getBody().toString());
606

    
607
        return repository;
608
    }
609

    
610
    private void storeRepository(Repository repository, Authentication authentication) throws Exception {
611

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

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

    
626
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
627
            try {
628
                emailUtils.sendUserRegistrationEmail(repository, authentication);
629
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
630
            } catch (Exception e) {
631
                LOGGER.error("Error sending emails: " + e);
632
            }
633
        } else {
634
            LOGGER.debug(responseEntity.getBody().toString());
635
        }
636
    }
637

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

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

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

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

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

    
667
        try {
668
            emailUtils.sendAdminRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
669
            emailUtils.sendUserRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
670
        } catch (Exception ex) {
671
            LOGGER.error("Error sending emails: " + ex);
672
        }
673

    
674
        submitInterfaceValidation(e, registeredBy, repositoryInterface, false);
675

    
676
        return repositoryInterface;
677
    }
678

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

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

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

    
700
        submitInterfaceValidation(getRepositoryById(repoId), registeredBy, repositoryInterface, true);
701

    
702
        return repositoryInterface;
703
    }
704

    
705
    private void submitInterfaceValidation(Repository repo, String userEmail, RepositoryInterface iFace, boolean updateExisting) throws ValidatorServiceException {
706
        JobForValidation job = new JobForValidation();
707

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

    
722
        this.validatorService.submitJobForValidation(job);
723
    }
724

    
725
    private RepositoryInterface createRepositoryInterface(Repository repo, RepositoryInterface iFace, String datatype) {
726

    
727
        iFace.setContentDescription("metadata");
728
        iFace.setCompliance("UNKNOWN");
729

    
730
        if (datatype.equals("re3data"))
731
            iFace.setAccessFormat("oai_datacite");
732
        else
733
            iFace.setAccessFormat("oai_dc");
734

    
735

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

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

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

    
765
    @Override
766
    public List<String> getTypologies() {
767
        return Converter.readFile("typologies.txt");
768
    }
769

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

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

    
785
        RequestFilter requestFilter = new RequestFilter();
786
        requestFilter.setRegisteredby(userEmail);
787
        return Arrays.asList(restTemplate.postForObject(uriComponents.toUri(), requestFilter, String[].class));
788
    }
789

    
790
    @Override
791
    public List<String> getDatasourceVocabularies(String mode) {
792

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

    
810

    
811
        return resultSet;
812
    }
813

    
814
    private Vocabulary getVocabulary(String vocName) {
815

    
816
        if (!vocabularyMap.containsKey(vocName)) {
817
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
818
        }
819
        return vocabularyMap.get(vocName);
820
    }
821

    
822

    
823
    @Override
824
    public Map<String, String> getCompatibilityClasses(String mode) {
825

    
826
        LOGGER.debug("Getting compatibility classes for mode: " + mode);
827
        Map<String, String> retMap = new HashMap<String, String>();
828

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

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

    
849
        return retMap;
850
    }
851

    
852
    @Override
853
    public Map<String, String> getDatasourceClasses(String mode) {
854

    
855
        LOGGER.debug("Getting datasource classes for mode: " + mode);
856

    
857
        Map<String, String> retMap = new HashMap<String, String>();
858

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

    
876
    }
877

    
878
    private Map<String, String> filterResults(Map<String, String> map, String mode) {
879

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

    
885
        return filteredMap;
886
    }
887

    
888
    @Override
889
    public String getCountryName(String countryCode) {
890
        return inverseCountriesMap.get(countryCode);
891
    }
892

    
893
    @Override
894
    public MetricsInfo getMetricsInfoForRepository(String repoId) throws RepositoryServiceException {
895
        try {
896

    
897
            MetricsInfo metricsInfo = new MetricsInfo();
898
            metricsInfo.setDiagramsBaseURL(this.usageStatisticsDiagramsBaseURL);
899
            metricsInfo.setMetricsNumbers(getMetricsNumbers(getOpenAIREId(repoId)));
900
            return metricsInfo;
901

    
902
        } catch (Exception e) {
903
            LOGGER.error("Error while getting metrics info for repository: ", e);
904
            throw new RepositoryServiceException("General error", RepositoryServiceException.ErrorCode.GENERAL_ERROR);
905
        }
906
    }
907

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

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

    
928
    }
929

    
930

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

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

    
951
    private MetricsNumbers getMetricsNumbers(String openAIREID) throws BrokerException {
952

    
953
        //build the uri params
954
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(this.usageStatisticsNumbersBaseURL + openAIREID + "/clicks");
955

    
956
        //create new template engine
957
        RestTemplate template = new RestTemplate();
958
        template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
959
        ResponseEntity<MetricsNumbers> resp;
960

    
961
        //communicate with endpoint
962
        resp = template.exchange(
963
                builder.build().encode().toUri(),
964
                HttpMethod.GET,
965
                null,
966
                new ParameterizedTypeReference<MetricsNumbers>() {
967
                });
968

    
969
        return resp.getBody();
970
    }
971

    
972
    private String getOpenAIREId(String repoId) {
973

    
974
        if (repoId != null && repoId.contains("::")) {
975
            return repoId.split("::")[0] + "::" + DigestUtils.md5Hex(repoId.split("::")[1]);
976
        }
977

    
978
        return null;
979
    }
980

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

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

    
991
    private UriComponents searchSnipperDatasource(String page, String size) {
992

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

    
1001
    private UriComponents searchRegisteredDatasource(String requestSortBy, String order, String page, String size) {
1002

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

    
1011
    private String getRepositoryType(String typology) {
1012
        return invertedDataSourceClass.get(typology);
1013
    }
1014

    
1015
    private List<String> getRoleIdsFromUserRoles(String userEmail) {
1016
        Integer coPersonId = registryCalls.getCoPersonIdByEmail(userEmail);
1017
        JsonArray roles;
1018
        ArrayList<String> roleIds = new ArrayList<>();
1019
        ArrayList<Integer> couIds = new ArrayList<>();
1020
        if (coPersonId != null) {
1021
            roles = registryCalls.getRolesWithStatus(coPersonId, AaiRegistryService.RoleStatus.ACTIVE);
1022
            for (JsonElement role : roles) {
1023
                JsonObject object = role.getAsJsonObject();
1024
                if (object.get("CouId") == null) {
1025
                    continue;
1026
                }
1027
                couIds.add(object.get("CouId").getAsInt());
1028
            }
1029

    
1030
            roleIds.addAll(registryCalls.getCouNames(couIds).values());
1031

    
1032
        }
1033
        return roleIds;
1034
    }
1035
}
(12-12/20)