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
    @PostConstruct
109
    private void init() {
110
        LOGGER.debug("Initialization method of repository api!");
111
        LOGGER.debug("Updated version!");
112

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

    
130
        for (Map.Entry<String, List<String>> entry : dataSourceClass.entrySet()) {
131
            entry.getValue().forEach(v -> invertedDataSourceClass.put(v, entry.getKey()));
132
        }
133

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

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

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

    
147

    
148
    }
149

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

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

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

    
180
            repos.addAll(Converter.jsonToRepositoryList(new JSONObject(rs)));
181
        }
182

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

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

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

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

    
208
        try {
209
            for (String repoId : ids) {
210
                requestFilter.setId(repoId);
211

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

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

    
229

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

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

    
241
        String filterKey = "UNKNOWN";
242
        if (mode.equalsIgnoreCase("opendoar"))
243
            filterKey = "openaire____::opendoar";
244
        else if (mode.equalsIgnoreCase("re3data"))
245
            filterKey = "openaire____::re3data";
246
        else if (mode.equalsIgnoreCase("cris"))
247
            filterKey = "eurocrisdris::dris";
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
            resultSet.addAll(mapper.readValue(String.valueOf(jsonArray),
263
                    mapper.getTypeFactory().constructCollectionType(List.class, RepositorySnippet.class)));
264
            page += 1;
265
            uriComponents = searchSnipperDatasource(String.valueOf(page), String.valueOf(size));
266
            rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
267
            jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
268
        }
269
        return resultSet;
270
    }
271

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

    
275
        LOGGER.debug("Searching registered repositories");
276

    
277
        List<RepositorySnippet> resultSet = new ArrayList<>();
278
        ObjectMapper mapper = new ObjectMapper();
279

    
280
        UriComponents uriComponents = searchRegisteredDatasource(requestSortBy, order, Integer.toString(page), Integer.toString(pageSize));
281

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

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

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

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

    
301
    @Override
302
    public int getTotalRegisteredRepositories() {
303
        UriComponents uriComponents = UriComponentsBuilder
304
                .fromHttpUrl(baseAddress + "/ds/countregistered")
305
                .queryParam("fromDate", "1900-01-01")
306
                .build().encode();
307

    
308
        return restTemplate.getForObject(uriComponents.toUri(), Integer.class);
309
    }
310

    
311
    private Repository updateRepositoryInfo(Repository r) throws JSONException {
312

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

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

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

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

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

    
351
    @Override
352
    public RepositorySnippet getRepositorySnippetById(String id) throws JSONException, ResourceNotFoundException {
353

    
354
        LOGGER.debug("Retrieving repositories with id : " + id);
355
        RepositorySnippet repo = null;
356
        UriComponents uriComponents = searchSnipperDatasource("0", "100");
357
        RequestFilter requestFilter = new RequestFilter();
358
        requestFilter.setId(id);
359

    
360
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
361
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
362

    
363
        if (jsonArray.length() == 0)
364
            throw new ResourceNotFoundException();
365

    
366
        repo = Converter.jsonToRepositorySnippetObject(jsonArray.getJSONObject(0));
367
        return repo;
368
    }
369

    
370
    @Override
371
    public Repository getRepositoryById(String id) throws JSONException, ResourceNotFoundException {
372

    
373
        LOGGER.debug("Retrieving repositories with id : " + id);
374
        Repository repo = null;
375
        UriComponents uriComponents = searchDatasource("0", "100");
376
        RequestFilter requestFilter = new RequestFilter();
377
        requestFilter.setId(id);
378

    
379
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
380
        JSONArray jsonArray = (JSONArray) new JSONObject(rs).get("datasourceInfo");
381

    
382
        if (jsonArray.length() == 0)
383
            throw new ResourceNotFoundException();
384

    
385
        repo = Converter.jsonToRepositoryObject(jsonArray.getJSONObject(0));
386
        return updateRepositoryInfo(repo);
387
    }
388

    
389

    
390
    @Override
391
    public List<AggregationDetails> getRepositoryAggregations(String id) throws JSONException {
392

    
393
        LOGGER.debug("Retrieving aggregations for repository with id : " + id);
394
        UriComponents uriComponents = getAggregationHistory(id);
395

    
396
        String rs = restTemplate.getForObject(uriComponents.toUri(), String.class);
397
        JSONArray aggregationInfo = new JSONObject(rs).getJSONArray("aggregationInfo");
398

    
399
        List<AggregationDetails> aggregationHistory = new ArrayList<>(Converter.getAggregationHistoryFromJson(aggregationInfo));
400

    
401
        return aggregationHistory;
402
    }
403

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

    
407
	List<AggregationDetails> res = getRepositoryAggregations(id);
408

    
409
	return res.subList(from, Math.min(from + size, res.size()));
410
    }
411

    
412
    @Override
413
    public Map<String, List<AggregationDetails>> getRepositoryAggregationsByYear(String id) throws JSONException {
414
        LOGGER.debug("Retrieving aggregations (by year) for repository with id : " + id);
415

    
416
        List<AggregationDetails> aggregationHistory = getRepositoryAggregations(id);
417
        Map<String, List<AggregationDetails>> aggregationByYear = new HashMap<>();
418
        
419
        return aggregationHistory.size() == 0 ? aggregationByYear : createYearMap(aggregationHistory);
420
    }
421

    
422
    private Map<String, List<AggregationDetails>> createYearMap(List<AggregationDetails> aggregationHistory) {
423
        
424
        aggregationHistory = aggregationHistory.stream()
425
                .sorted(Comparator.comparing(AggregationDetails::getDate).reversed())
426
                .collect(Collectors.toList());
427

    
428
        return aggregationHistory.stream()
429
                .collect(Collectors.groupingBy(AggregationDetails::getYear));
430
    }
431

    
432

    
433
    @Override
434
    public List<Repository> getRepositoriesByName(String name,
435
                                                  String page,
436
                                                  String size) throws JSONException {
437

    
438
        LOGGER.debug("Retrieving  repositories with official name : " + name);
439
        UriComponents uriComponents = searchDatasource("0", "100");
440
        RequestFilter requestFilter = new RequestFilter();
441
        requestFilter.setOfficialname(name);
442

    
443
        String rs = restTemplate.postForObject(uriComponents.toUri(), requestFilter, String.class);
444
        List<Repository> repos = Converter.jsonToRepositoryList(new JSONObject(rs));
445
        for (Repository r : repos)
446
            updateRepositoryInfo(r);
447
        return repos;
448

    
449
    }
450

    
451
    @Override
452
    public List<RepositoryInterface> getRepositoryInterface(String id) throws JSONException {
453

    
454
        UriComponents uriComponents = UriComponentsBuilder
455
                .fromHttpUrl(baseAddress + "/ds/api/")
456
                .path("/{id}")
457
                .build().expand(id).encode();
458

    
459
        String rs = restTemplate.getForObject(uriComponents.toUri(), String.class);
460
        return Converter.jsonToRepositoryInterfaceList(new JSONObject(rs));
461

    
462
    }
463

    
464
    @Override
465
    public Repository addRepository(String datatype, Repository repository) throws Exception {
466

    
467
        LOGGER.debug("storing " + datatype + " repository with id: " + repository.getId());
468

    
469
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
470
        repository.setActivationId(UUID.randomUUID().toString());
471
        repository.setCollectedFrom("infrastruct_::openaire");
472

    
473
        if (datatype.equals("journal")) {
474
            repository.setId("openaire____::issn" + repository.getIssn());
475
            repository.setNamespacePrefix("issn" + repository.getIssn());
476
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
477
        } else if (datatype.equals("aggregator")) {
478
            repository.setId("openaire____::" + DigestUtils.md5Hex(repository.getOfficialName()));
479
            repository.setNamespacePrefix(DigestUtils.md5Hex(repository.getOfficialName()).substring(0, 12));
480
            this.storeRepository(repository, SecurityContextHolder.getContext().getAuthentication());
481
        } else {
482
            this.latentUpdate(repository, SecurityContextHolder.getContext().getAuthentication());
483
        }
484

    
485
        // TODO: move the following code elsewhere (creation and assignment of role to user) ??
486
        // Create new role
487
        String newRoleName = roleMappingService.getRoleIdByRepoId(repository.getId());
488
        Role newRole = new Role(newRoleName, repository.getOfficialName());
489
        Integer couId = null;
490
        try {
491
            couId = registryCalls.createRole(newRole);
492
        } catch (HttpClientErrorException e) {
493
            couId = registryCalls.getCouId(newRoleName);
494
            if (couId == null) {
495
                LOGGER.error(String.format("Could not create role '%s'", newRoleName), e);
496
            }
497
        } catch (Exception e) {
498
            LOGGER.error(String.format("Could not create role '%s'", newRoleName), e);
499
            throw e;
500
        }
501

    
502
        // Assign new role to the user that created it
503
        Integer coPersonId = registryCalls.getCoPersonIdByIdentifier();
504
        if (couId != null) {
505
            Integer role = registryCalls.getRoleId(coPersonId, couId);
506
            try {
507
                registryCalls.assignMemberRole(coPersonId, couId, role);
508

    
509
                // Add role to current user authorities
510
                authoritiesUpdater.addRole(roleMappingService.convertRepoIdToAuthority(repository.getId()));
511
            } catch (Exception e) {
512
                LOGGER.debug("Exception on assign role to user during add repository", e);
513
                throw e;
514
            }
515

    
516
        }
517

    
518

    
519
        return repository;
520
    }
521

    
522
    /* update method acting as add -> send email with registration topic/body*/
523
    private Repository latentUpdate(Repository repository, Authentication authentication) throws Exception {
524
        UriComponents uriComponents = UriComponentsBuilder
525
                .fromHttpUrl(baseAddress + "/ds/update/")
526
                .build()
527
                .encode();
528

    
529
        String json_repository = Converter.repositoryObjectToJson(repository);
530
        LOGGER.debug("JSON to add(update) -> " + json_repository);
531

    
532
        HttpEntity<String> httpEntity = new HttpEntity<>(json_repository, httpHeaders);
533
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
534

    
535
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
536
            try {
537
                emailUtils.sendUserRegistrationEmail(repository, authentication);
538
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
539
            } catch (Exception e) {
540
                LOGGER.error("Error sending email", e);
541
            }
542
        } else
543
            LOGGER.error("Error storing repository: " + responseEntity.getBody().toString());
544

    
545
        return repository;
546
    }
547

    
548
    @Override
549
    public Repository updateRepository(Repository repository, Authentication authentication) throws Exception {
550
        UriComponents uriComponents = UriComponentsBuilder
551
                .fromHttpUrl(baseAddress + "/ds/update/")
552
                .build()
553
                .encode();
554

    
555
        String json_repository = Converter.repositoryObjectToJson(repository);
556

    
557
        LOGGER.debug("JSON to update -> " + json_repository);
558

    
559
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
560
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity
561
                , ResponseEntity.class);
562

    
563
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
564
            try {
565
                emailUtils.sendUserUpdateRepositoryInfoEmail(repository, authentication);
566
                emailUtils.sendAdminUpdateRepositoryInfoEmail(repository, authentication);
567
            } catch (Exception e) {
568
                LOGGER.error("Error sending emails: " + e);
569
            }
570
        } else
571
            LOGGER.debug(responseEntity.getBody().toString());
572

    
573
        return repository;
574
    }
575

    
576
    private void storeRepository(Repository repository, Authentication authentication) throws Exception {
577

    
578
        Date utilDate = new Date();
579
        Timestamp date = new Timestamp(utilDate.getTime());
580
        repository.setDateOfCollection(date);
581
        repository.setAggregator("OPENAIRE");
582
        repository.setCountryCode(countriesMap.get(repository.getCountryName()));
583

    
584
        UriComponents uriComponents = UriComponentsBuilder
585
                .fromHttpUrl(baseAddress + "/ds/add/")
586
                .build()
587
                .encode();
588
        String json_repository = Converter.repositoryObjectToJson(repository);
589
        HttpEntity<String> httpEntity = new HttpEntity<String>(json_repository, httpHeaders);
590
        ResponseEntity responseEntity = restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, httpEntity, ResponseEntity.class);
591

    
592
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
593
            try {
594
                emailUtils.sendUserRegistrationEmail(repository, authentication);
595
                emailUtils.sendAdminRegistrationEmail(repository, authentication);
596
            } catch (Exception e) {
597
                LOGGER.error("Error sending emails: " + e);
598
            }
599
        } else {
600
            LOGGER.debug(responseEntity.getBody().toString());
601
        }
602
    }
603

    
604
    @Override
605
    public void deleteRepositoryInterface(String id,
606
                                          String registeredBy) {
607
        UriComponents uriComponents = UriComponentsBuilder
608
                .fromHttpUrl(baseAddress + "/ds/api/")
609
                .path("/{id}")
610
                .build().expand(id).encode();
611
        LOGGER.debug(uriComponents.toUri());
612
        restTemplate.delete(uriComponents.toUri());
613
    }
614

    
615
    @Override
616
    public RepositoryInterface addRepositoryInterface(String datatype,
617
                                                      String repoId,
618
                                                      String registeredBy,
619
                                                      String comment, RepositoryInterface repositoryInterface) throws Exception {
620
        Repository e = this.getRepositoryById(repoId);
621
        repositoryInterface = createRepositoryInterface(e, repositoryInterface, datatype);
622
        String json_interface = Converter.repositoryInterfaceObjectToJson(e, repositoryInterface);
623

    
624
        UriComponents uriComponents = UriComponentsBuilder
625
                .fromHttpUrl(baseAddress + "/ds/api/add/")
626
                .build()
627
                .encode();
628

    
629
        HttpEntity<String> httpEntity = new HttpEntity<>(json_interface, httpHeaders);
630

    
631
        restTemplate.postForObject(uriComponents.toUri(), httpEntity, String.class);
632

    
633
        try {
634
            emailUtils.sendAdminRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
635
            emailUtils.sendUserRegisterInterfaceEmail(e, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
636
        } catch (Exception ex) {
637
            LOGGER.error("Error sending emails: " + ex);
638
        }
639

    
640
        submitInterfaceValidation(e, registeredBy, repositoryInterface, false);
641

    
642
        return repositoryInterface;
643
    }
644

    
645
    @Override
646
    public RepositoryInterface updateRepositoryInterface(String repoId,
647
                                                         String registeredBy,
648
                                                         String comment, RepositoryInterface repositoryInterface) throws Exception {
649

    
650
        this.updateBaseUrl(repoId, repositoryInterface.getId(), repositoryInterface.getBaseUrl());
651
        this.updateCompliance(repoId, repositoryInterface.getId(), repositoryInterface.getCompliance());
652
        this.updateValidationSet(repoId, repositoryInterface.getId(), repositoryInterface.getAccessSet());
653

    
654
        Repository repository = this.getRepositoryById(repoId);
655
        try {
656
            try {
657
                emailUtils.sendAdminUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
658
                emailUtils.sendUserUpdateInterfaceEmail(repository, comment, repositoryInterface, SecurityContextHolder.getContext().getAuthentication());
659
            } catch (Exception e) {
660
                LOGGER.error("Error sending emails: " + e);
661
            }
662
        } catch (Exception e) {
663
            LOGGER.warn("Could not send emails", e);
664
        }
665

    
666
        submitInterfaceValidation(getRepositoryById(repoId), registeredBy, repositoryInterface, true);
667

    
668
        return repositoryInterface;
669
    }
670

    
671
    private void submitInterfaceValidation(Repository repo, String userEmail, RepositoryInterface iFace, boolean updateExisting) throws ValidatorServiceException {
672
        JobForValidation job = new JobForValidation();
673

    
674
        job.setActivationId(UUID.randomUUID().toString());
675
        job.setAdminEmails(Collections.singletonList(this.adminEmail));
676
        job.setBaseUrl(iFace.getBaseUrl());
677
        job.setDatasourceId(repo.getId());
678
        job.setDesiredCompatibilityLevel(iFace.getDesiredCompatibilityLevel());
679
        job.setInterfaceId(iFace.getId());
680
        job.setOfficialName(repo.getOfficialName());
681
        job.setRepoType(repo.getDatasourceType());
682
        job.setUserEmail(userEmail);
683
        job.setValidationSet((iFace.getAccessSet().isEmpty() ? "none" : iFace.getAccessSet()));
684
        job.setRecords(-1);
685
        job.setRegistration(!updateExisting);
686
        job.setUpdateExisting(updateExisting);
687

    
688
        this.validatorService.submitJobForValidation(job);
689
    }
690

    
691
    private RepositoryInterface createRepositoryInterface(Repository repo, RepositoryInterface iFace, String datatype) {
692

    
693
        iFace.setContentDescription("metadata");
694
        iFace.setCompliance("UNKNOWN");
695

    
696
        if (datatype.equals("re3data"))
697
            iFace.setAccessFormat("oai_datacite");
698
        else
699
            iFace.setAccessFormat("oai_dc");
700

    
701

    
702
        if (repo.getDatasourceClass() != null && !repo.getDatasourceClass().isEmpty())
703
            iFace.setTypology(repo.getDatasourceClass());
704
        else if (datatype.equalsIgnoreCase("journal"))
705
            iFace.setTypology("pubsrepository::journal");
706
        else if (datatype.equalsIgnoreCase("aggregator"))
707
            iFace.setTypology("aggregator::pubsrepository::unknown");
708
        else if (datatype.equalsIgnoreCase("opendoar"))
709
            iFace.setTypology("pubsrepository::unknown");
710
        else if (datatype.equalsIgnoreCase("re3data"))
711
            iFace.setTypology("datarepository::unknown");
712

    
713
        iFace.setRemovable(true);
714
        iFace.setAccessProtocol("oai");
715
        iFace.setMetadataIdentifierPath("//*[local-name()='header']/*[local-name()='identifier']");
716
        iFace.setId("api_________::" + repo.getId() + "::" + UUID.randomUUID().toString().substring(0, 8));
717
        if (iFace.getAccessSet() == null || iFace.getAccessSet().isEmpty()) {
718
            LOGGER.debug("set is empty: " + iFace.getAccessSet());
719
            iFace.removeAccessSet();
720
            iFace.setAccessSet("none");
721
        }
722
        return iFace;
723
    }
724

    
725
    @Override
726
    public List<String> getDnetCountries() {
727
        LOGGER.debug("Getting dnet-countries!");
728
        return Converter.readFile("countries.txt");
729
    }
730

    
731
    @Override
732
    public List<String> getTypologies() {
733
        return Converter.readFile("typologies.txt");
734
    }
735

    
736
    @Override
737
    public List<Timezone> getTimezones() {
738
        List<String> timezones = Converter.readFile("timezones.txt");
739
        return Converter.toTimezones(timezones);
740
    }
741

    
742
    @Override
743
    public List<String> getUrlsOfUserRepos(String userEmail,
744
                                           String page,
745
                                           String size) {
746
        UriComponents uriComponents = UriComponentsBuilder
747
                .fromHttpUrl(baseAddress + "/api/baseurl/")
748
                .path("/{page}/{size}")
749
                .build().expand(page, size).encode();
750

    
751
        RequestFilter requestFilter = new RequestFilter();
752
        requestFilter.setRegisteredby(userEmail);
753
        return Arrays.asList(restTemplate.postForObject(uriComponents.toUri(), requestFilter, String[].class));
754
    }
755

    
756
    private Vocabulary getVocabulary(String vocName) {
757

    
758
        if (!vocabularyMap.containsKey(vocName)) {
759
            vocabularyMap.put(vocName, vocabularyLoader.getVocabulary(vocName, Locale.ENGLISH, Locale.ROOT));
760
        }
761
        return vocabularyMap.get(vocName);
762
    }
763

    
764

    
765
    @Override
766
    public Map<String, String> getCompatibilityClasses(String mode) {
767

    
768
        LOGGER.debug("Getting compatibility classes for mode: " + mode);
769
        Map<String, String> retMap = new HashMap<String, String>();
770

    
771
        Map<String, String> compatibilityClasses = this.getVocabulary("dnet:compatibilityLevel").getAsMap();
772
        boolean foundData = false;
773
        for (Map.Entry<String, String> entry : compatibilityClasses.entrySet()) {
774
            if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_ALL))
775
                return compatibilityClasses;
776
            else if (mode.equalsIgnoreCase(Constants.REPOSITORY_MODE_RE3DATA)) {
777
                if (entry.getKey().matches("^openaire[1-9].0_data$")) {
778
                    retMap.put(entry.getKey(), entry.getValue());
779
                    foundData = true;
780
                }
781
            }
782
            else if (mode.equalsIgnoreCase("cris")) {
783
                if (entry.getKey().contains("openaire-cris")) {
784
                    retMap.put(entry.getKey(), entry.getValue());
785
                    foundData = true;
786
                }
787
            } else {
788
                if (entry.getKey().matches("^openaire[1-9].0$") || entry.getKey().equals("driver"))
789
                    retMap.put(entry.getKey(), entry.getValue());
790
            }
791
        }
792

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

    
797
        return retMap;
798
    }
799

    
800
    @Override
801
    public Map<String, String> getDatasourceClasses(String mode) {
802

    
803
        LOGGER.debug("Getting datasource classes for mode: " + mode);
804

    
805
        Map<String, String> retMap = new HashMap<String, String>();
806

    
807
        for (Map.Entry<String, String> entry : this.getVocabulary("dnet:datasource_typologies").getAsMap().entrySet()) {
808
            if (mode.equalsIgnoreCase("aggregator")) {
809
                if (entry.getKey().contains("aggregator"))
810
                    retMap.put(entry.getKey(), entry.getValue());
811
            } else if (mode.equalsIgnoreCase("journal")) {
812
                if (entry.getKey().contains("journal"))
813
                    retMap.put(entry.getKey(), entry.getValue());
814
            } else if (mode.equalsIgnoreCase("opendoar")) {
815
                if (entry.getKey().contains("pubsrepository"))
816
                    retMap.put(entry.getKey(), entry.getValue());
817
            } else if (mode.equalsIgnoreCase("re3data")) {
818
                if (entry.getKey().contains("datarepository"))
819
                    retMap.put(entry.getKey(), entry.getValue());
820
            } else if (mode.equalsIgnoreCase("cris")) {
821
                if (entry.getKey().contains("crissystem"))
822
                    retMap.put(entry.getKey(), entry.getValue());
823
            }
824
        }
825
        return filterResults(retMap, mode);
826

    
827
    }
828

    
829
    private Map<String, String> filterResults(Map<String, String> map, String mode) {
830

    
831
        HashMap<String, String> filteredMap = new HashMap<>();
832
        for (String key : map.keySet())
833
            if (dataSourceClass.get(mode).contains(key))
834
                filteredMap.put(key, map.get(key));
835

    
836
        return filteredMap;
837
    }
838

    
839
    @Override
840
    public String getCountryName(String countryCode) {
841
        return inverseCountriesMap.get(countryCode);
842
    }
843

    
844
    @Override
845
    public MetricsInfo getMetricsInfoForRepository(String repoId) throws RepositoryServiceException {
846
        try {
847

    
848
            MetricsInfo metricsInfo = new MetricsInfo();
849
            metricsInfo.setDiagramsBaseURL(this.usageStatisticsDiagramsBaseURL);
850
            metricsInfo.setMetricsNumbers(getMetricsNumbers(getOpenAIREId(repoId)));
851
            return metricsInfo;
852

    
853
        } catch (Exception e) {
854
            LOGGER.error("Error while getting metrics info for repository: ", e);
855
            throw new RepositoryServiceException("General error", RepositoryServiceException.ErrorCode.GENERAL_ERROR);
856
        }
857
    }
858

    
859
    @Override
860
    public Map<String, String> getListLatestUpdate(String mode) throws JSONException {
861
        if (mode.equals("opendoar"))
862
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(0).getLastCollectionDate());
863
        else if (mode.equals("cris"))
864
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("eurocrisdris::dris").get(0).getLastCollectionDate());
865
        else
866
            /*
867
             * first api of re3data has null value on collection date
868
             * */
869
            return Collections.singletonMap("lastCollectionDate", getRepositoryInterface("openaire____::" + mode).get(1).getLastCollectionDate());
870
    }
871

    
872
    private void updateValidationSet(String repositoryId, String repositoryInterfaceId, String validationSet) throws Exception {
873
        UriComponents uriComponents = UriComponentsBuilder
874
                .fromHttpUrl(baseAddress + "/ds/api/oaiset")
875
                .queryParam("dsId", repositoryId)
876
                .queryParam("apiId", repositoryInterfaceId)
877
                .queryParam("oaiSet", validationSet)
878
                .build().encode();
879
        restTemplate.exchange(uriComponents.toUri(), HttpMethod.POST, null, ResponseEntity.class);
880

    
881
    }
882

    
883

    
884
    private void updateBaseUrl(String repositoryId, String repositoryInterfaceId, String baseUrl) {
885
        UriComponents uriComponents = UriComponentsBuilder
886
                .fromHttpUrl(baseAddress + "/ds/api/baseurl")
887
                .queryParam("dsId", repositoryId)
888
                .queryParam("apiId", repositoryInterfaceId)
889
                .queryParam("baseUrl", baseUrl)
890
                .build().encode();
891
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
892
    }
893

    
894
    private void updateCompliance(String repositoryId, String repositoryInterfaceId, String compliance) {
895
        UriComponents uriComponents = UriComponentsBuilder
896
                .fromHttpUrl(baseAddress + "/ds/api/compliance")
897
                .queryParam("dsId", repositoryId)
898
                .queryParam("apiId", repositoryInterfaceId)
899
                .queryParam("compliance", compliance)
900
                .build().encode();
901
        restTemplate.postForObject(uriComponents.toUri(), null, String.class);
902
    }
903

    
904
    private MetricsNumbers getMetricsNumbers(String openAIREID) throws BrokerException {
905

    
906
        //build the uri params
907
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(this.usageStatisticsNumbersBaseURL + openAIREID + "/clicks");
908

    
909
        //create new template engine
910
        RestTemplate template = new RestTemplate();
911
        template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
912
        ResponseEntity<MetricsNumbers> resp;
913

    
914
        //communicate with endpoint
915
        resp = template.exchange(
916
                builder.build().encode().toUri(),
917
                HttpMethod.GET,
918
                null,
919
                new ParameterizedTypeReference<MetricsNumbers>() {
920
                });
921

    
922
        return resp.getBody();
923
    }
924

    
925
    private String getOpenAIREId(String repoId) {
926

    
927
        if (repoId != null && repoId.contains("::")) {
928
            return repoId.split("::")[0] + "::" + DigestUtils.md5Hex(repoId.split("::")[1]);
929
        }
930

    
931
        return null;
932
    }
933

    
934
    private UriComponents getAggregationHistory(String repoId) {
935
        return UriComponentsBuilder
936
                .fromHttpUrl(baseAddress + "/ds/aggregationhistory/")
937
                .path(repoId)
938
                .build().expand(repoId).encode();
939
    }
940

    
941
    private UriComponents searchDatasource(String page, String size) {
942

    
943
        return UriComponentsBuilder
944
                .fromHttpUrl(baseAddress + "/ds/searchdetails/")
945
                .path("/{page}/{size}/")
946
                .queryParam("requestSortBy", "officialname")
947
                .queryParam("order", "ASCENDING")
948
                .build().expand(page, size).encode();
949
    }
950

    
951
    private UriComponents searchSnipperDatasource(String page, String size) {
952

    
953
        return UriComponentsBuilder
954
                .fromHttpUrl(baseAddress + "/ds/searchsnippet/")
955
                .path("/{page}/{size}/")
956
                .queryParam("requestSortBy", "officialname")
957
                .queryParam("order", "ASCENDING")
958
                .build().expand(page, size).encode();
959
    }
960

    
961
    private UriComponents searchRegisteredDatasource(String requestSortBy, String order, String page, String size) {
962

    
963
        return UriComponentsBuilder
964
                .fromHttpUrl(baseAddress + "/ds/searchregistered/")
965
                .path("/{page}/{size}/")
966
                .queryParam("requestSortBy", requestSortBy)
967
                .queryParam("order", order)
968
                .build().expand(page, size).encode();
969
    }
970

    
971
    private String getRepositoryType(String typology) {
972
        return invertedDataSourceClass.get(typology);
973
    }
974

    
975
    private List<String> getRoleIdsFromUserRoles(String userEmail) {
976
        Integer coPersonId = registryCalls.getCoPersonIdByEmail(userEmail);
977
        JsonArray roles;
978
        ArrayList<String> roleIds = new ArrayList<>();
979
        ArrayList<Integer> couIds = new ArrayList<>();
980
        if (coPersonId != null) {
981
            roles = registryCalls.getRolesWithStatus(coPersonId, AaiRegistryService.RoleStatus.ACTIVE);
982
            for (JsonElement role : roles) {
983
                JsonObject object = role.getAsJsonObject();
984
                if (object.get("CouId") == null) {
985
                    continue;
986
                }
987
                couIds.add(object.get("CouId").getAsInt());
988
            }
989

    
990
            roleIds.addAll(registryCalls.getCouNames(couIds).values());
991

    
992
        }
993
        return roleIds;
994
    }
995
}
(12-12/20)