Project

General

Profile

Download (16.2 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2017 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.dataInserter;
10

    
11
import java.io.IOException;
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.EnumSet;
15
import java.util.HashMap;
16
import java.util.HashSet;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.Set;
20
import java.util.UUID;
21

    
22
import org.apache.log4j.Logger;
23
import org.joda.time.DateTime;
24
import org.joda.time.Partial;
25
import org.joda.time.format.DateTimeFormatter;
26
import org.springframework.context.event.ContextRefreshedEvent;
27
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
28
import org.springframework.security.core.GrantedAuthority;
29
import org.springframework.transaction.TransactionStatus;
30

    
31
import com.fasterxml.jackson.core.JsonParseException;
32
import com.fasterxml.jackson.databind.JsonMappingException;
33
import com.fasterxml.jackson.databind.ObjectMapper;
34

    
35
import eu.etaxonomy.cdm.api.application.AbstractDataInserter;
36
import eu.etaxonomy.cdm.api.application.CdmRepository;
37
import eu.etaxonomy.cdm.api.service.pager.Pager;
38
import eu.etaxonomy.cdm.model.agent.AgentBase;
39
import eu.etaxonomy.cdm.model.agent.Institution;
40
import eu.etaxonomy.cdm.model.common.ExtensionType;
41
import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
42
import eu.etaxonomy.cdm.model.common.Group;
43
import eu.etaxonomy.cdm.model.common.TimePeriod;
44
import eu.etaxonomy.cdm.model.name.Registration;
45
import eu.etaxonomy.cdm.model.name.RegistrationStatus;
46
import eu.etaxonomy.cdm.model.name.TaxonName;
47
import eu.etaxonomy.cdm.model.name.TypeDesignationBase;
48
import eu.etaxonomy.cdm.model.reference.Reference;
49
import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
50
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
51
import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
52
import eu.etaxonomy.cdm.persistence.hibernate.permission.Role;
53
import eu.etaxonomy.cdm.persistence.query.MatchMode;
54
import eu.etaxonomy.cdm.vaadin.model.registration.DerivationEventTypes;
55
import eu.etaxonomy.cdm.vaadin.security.RolesAndPermissions;
56

    
57
/**
58
 * @author a.kohlbecker
59
 * @since May 9, 2017
60
 *
61
 */
62
public class RegistrationRequiredDataInserter extends AbstractDataInserter {
63

    
64
    protected static final String PARAM_NAME_CREATE = "registrationCreate";
65

    
66
    protected static final String PARAM_NAME_WIPEOUT = "registrationWipeout";
67

    
68
    protected static final UUID GROUP_SUBMITTER_UUID = UUID.fromString("c468c6a7-b96c-4206-849d-5a825f806d3e");
69

    
70
    protected static final UUID GROUP_CURATOR_UUID = UUID.fromString("135210d3-3db7-4a81-ab36-240444637d45");
71

    
72
    private static final EnumSet<CRUD> CREATE_READ = EnumSet.of(CRUD.CREATE, CRUD.READ);
73
    private static final EnumSet<CRUD> CREATE_READ_UPDATE_DELETE = EnumSet.of(CRUD.CREATE, CRUD.READ, CRUD.UPDATE, CRUD.DELETE);
74

    
75
    private static final Logger logger = Logger.getLogger(RegistrationRequiredDataInserter.class);
76

    
77
    private ExtensionType extensionTypeIAPTRegData;
78

    
79
    Map<String, Institution> instituteMap = new HashMap<>();
80

    
81
    public static boolean commandsExecuted = false;
82

    
83
    private CdmRepository repo;
84

    
85
    private boolean hasRun = false;
86

    
87
    public void setCdmRepository(CdmRepository repo){
88
      this.repo = repo;
89
    }
90

    
91

    
92
 // ==================== Registration creation ======================= //
93

    
94
    /**
95
     * {@inheritDoc}
96
     */
97
    @Override
98
    public void onApplicationEvent(ContextRefreshedEvent event) {
99

    
100
        if(hasRun){
101
            return;
102
        }
103

    
104
        runAsAuthentication(Role.ROLE_ADMIN);
105

    
106
        insertRequiredData();
107
        executeSuppliedCommands();
108

    
109
        restoreAuthentication();
110

    
111
        hasRun = true;
112
    }
113

    
114
    /**
115
     *
116
     */
117
    private void insertRequiredData() {
118

    
119
        Role roleCuration = RolesAndPermissions.ROLE_CURATION;
120
        if(repo.getGrantedAuthorityService().find(roleCuration.getUuid()) == null){
121
            repo.getGrantedAuthorityService().saveOrUpdate(roleCuration.asNewGrantedAuthority());
122
        }
123

    
124
        Group groupCurator = repo.getGroupService().load(GROUP_CURATOR_UUID, Arrays.asList("grantedAuthorities"));
125
        if(groupCurator == null){
126
            groupCurator = Group.NewInstance();
127
            groupCurator.setUuid(GROUP_CURATOR_UUID);
128
            groupCurator.setName("Curator");
129
        }
130
        assureGroupHas(groupCurator, new CdmAuthority(CdmPermissionClass.REGISTRATION, CREATE_READ_UPDATE_DELETE).toString());
131
        repo.getGroupService().saveOrUpdate(groupCurator);
132

    
133
        Group groupSubmitter = repo.getGroupService().load(GROUP_SUBMITTER_UUID, Arrays.asList("grantedAuthorities"));
134
        if(groupSubmitter == null){
135
            groupSubmitter = Group.NewInstance();
136
            groupSubmitter.setUuid(GROUP_SUBMITTER_UUID);
137
            groupSubmitter.setName("Submitter");
138
        }
139
        assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.TAXONNAME, CREATE_READ).toString());
140
        assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.TEAMORPERSONBASE, CREATE_READ).toString());
141
        assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.REGISTRATION, CREATE_READ).toString());
142
        assureGroupHas(groupSubmitter, new CdmAuthority(CdmPermissionClass.SPECIMENOROBSERVATIONBASE, CREATE_READ).toString());
143
        repo.getGroupService().saveOrUpdate(groupSubmitter);
144

    
145
        if(repo.getTermService().find(DerivationEventTypes.PUBLISHED_IMAGE().getUuid()) == null){
146
            repo.getTermService().save(DerivationEventTypes.PUBLISHED_IMAGE());
147
        }
148
        if(repo.getTermService().find(DerivationEventTypes.UNPUBLISHED_IMAGE().getUuid()) == null){
149
            repo.getTermService().save(DerivationEventTypes.UNPUBLISHED_IMAGE());
150
        }
151
        if(repo.getTermService().find(DerivationEventTypes.CULTURE_METABOLIC_INACTIVE().getUuid()) == null){
152
            repo.getTermService().save(DerivationEventTypes.CULTURE_METABOLIC_INACTIVE());
153
        }
154
        repo.getSession().flush();
155

    
156
    }
157

    
158
    private void assureGroupHas(Group group, String authorityString){
159
        boolean authorityExists = false;
160

    
161
        for(GrantedAuthority ga : group.getGrantedAuthorities()){
162
            if((authorityExists = ga.getAuthority().equals(authorityString)) == true){
163
                break;
164
            }
165
        }
166
        if(!authorityExists){
167
            group.addGrantedAuthority(findGrantedAuthority(authorityString));
168
        }
169
    }
170

    
171
    private GrantedAuthorityImpl findGrantedAuthority(String authorityString){
172
        GrantedAuthorityImpl ga = null;
173
        try{
174
            ga = repo.getGrantedAuthorityService().findAuthorityString(authorityString);
175
        } catch (AuthenticationCredentialsNotFoundException e){
176
            e.printStackTrace();
177
        }
178
        if(ga == null){
179
            ga = GrantedAuthorityImpl.NewInstance(authorityString);
180
            repo.getGrantedAuthorityService().save(ga);
181
        }
182
        return ga;
183
    }
184

    
185
    /**
186
     *
187
     */
188

    
189
    private void executeSuppliedCommands() {
190

    
191
        if(commandsExecuted){
192
            // do not run twice
193
            // a second run could take place during initialization of the web context
194
            return;
195
        }
196
        commandsExecuted  = true;
197

    
198
        String wipeoutCmd = System.getProperty(PARAM_NAME_WIPEOUT);
199
        String createCmd = System.getProperty(PARAM_NAME_CREATE);
200

    
201
        // ============ DELETE
202
        if(wipeoutCmd != null && wipeoutCmd.matches("iapt|all")){
203

    
204
            boolean onlyIapt = wipeoutCmd.equals("iapt");
205
            List<UUID> deleteCandidates = new ArrayList<UUID>();
206

    
207
            TransactionStatus tx = repo.startTransaction(true);
208
            List<Registration> allRegs = repo.getRegistrationService().list(null, null, null, null, null);
209
            for(Registration reg : allRegs){
210
                if(onlyIapt){
211
                    try {
212
                        @SuppressWarnings("unchecked")
213
                        Set<String> extensions = reg.getName().getExtensions(getExtensionTypeIAPTRegData());
214
                        deleteCandidates.add(reg.getUuid());
215
                    } catch(NullPointerException e){
216
                        // IGNORE
217
                    }
218
                } else {
219
                    deleteCandidates.add(reg.getUuid());
220
                }
221
            }
222
            repo.commitTransaction(tx);
223
            repo.getRegistrationService().delete(deleteCandidates);
224
        }
225

    
226
        // ============ CREATE
227
        int pageIndex = 0;
228
        if(createCmd != null && createCmd.equals("iapt")){
229

    
230
            DateTimeFormatter dateFormat1 = org.joda.time.format.DateTimeFormat.forPattern("dd.MM.yy").withPivotYear(1950);
231
            DateTimeFormatter dateFormat2 = org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd").withPivotYear(1950);
232

    
233
            TransactionStatus tx = repo.startTransaction(false);
234
            while(true) {
235
                Pager<TaxonName> pager = repo.getNameService().page(null, 1000, pageIndex, null, null);
236
                if(pager.getRecords().isEmpty()){
237
                    break;
238
                }
239
                List<Registration> newRegs = new ArrayList<>(pager.getRecords().size());
240
                for(TaxonName name : pager.getRecords()){
241

    
242
                    Set<String> extensionValues = name.getExtensions(getExtensionTypeIAPTRegData());
243

    
244
                    // there is for sure only one
245
                    if(extensionValues.isEmpty()){
246
                        continue;
247
                    }
248
                    String iaptJson = extensionValues.iterator().next();
249
                    try {
250

    
251
                        IAPTRegData iaptData = new ObjectMapper().readValue(iaptJson, IAPTRegData.class);
252

    
253
                        if(iaptData.getRegId() == null){
254
                            continue;
255
                        }
256

    
257
                        DateTime regDate = null;
258
                        if(iaptData.getDate() != null){
259
                            DateTimeFormatter dateFormat;
260
                            if(iaptData.getDate().matches("\\d{4}-\\d{2}-\\d{2}")){
261
                                dateFormat = dateFormat2;
262
                            } else {
263
                                dateFormat = dateFormat1;
264
                            }
265
                            try {
266
                                regDate = dateFormat.parseDateTime(iaptData.getDate());
267
                                regDate.getYear();
268
                            } catch (Exception e) {
269
                                logger.error("Error parsing date : " + iaptData.getDate(), e);
270
                                continue;
271
                            }
272
                        }
273

    
274
                        Registration reg = Registration.NewInstance();
275
                        reg.setStatus(RegistrationStatus.PUBLISHED);
276
                        reg.setIdentifier("http://phycobank.org/" + iaptData.getRegId());
277
                        reg.setSpecificIdentifier(iaptData.getRegId().toString());
278
                        reg.setInstitution(getInstitution(iaptData.getOffice()));
279

    
280
                        boolean isPhycobankID = false; // Integer.valueOf(reg.getSpecificIdentifier()) >= 100000;
281

    
282
                        Partial youngestDate = null;
283
                        Reference youngestPub = null;
284

    
285
                        // find youngest publication
286

    
287
                        // NOTE:
288
                        // data imported from IAPT does not have typedesignation citations and sometimes no nomref
289

    
290
                        if(isPhycobankID){
291
                            youngestPub = (Reference) name.getNomenclaturalReference();
292
                            youngestDate = partial(youngestPub.getDatePublished());
293

    
294
                            if(name.getTypeDesignations() != null && !name.getTypeDesignations().isEmpty()){
295
                                for(TypeDesignationBase td : name.getTypeDesignations()){
296
                                    if(td.getCitation() == null){
297
                                        continue;
298
                                    }
299
                                    Partial pubdate = partial(td.getCitation().getDatePublished());
300
                                        if(youngestDate.compareTo(pubdate) < 0){
301
                                            youngestDate = pubdate;
302
                                            youngestPub = td.getCitation();
303
                                        }
304
                                }
305
                            }
306
                        }
307

    
308
                        if((isPhycobankID && youngestPub == name.getNomenclaturalReference()) || !isPhycobankID) {
309
                            reg.setName(name);
310
                        } else {
311
                            logger.debug("skipping name published in older referece");
312
                        }
313
                        if(name.getTypeDesignations() != null && !name.getTypeDesignations().isEmpty()){
314
                            // do not add the collection directly to avoid "Found shared references to a collection" problem
315
                            HashSet<TypeDesignationBase> typeDesignations = new HashSet<>(name.getTypeDesignations().size());
316
                            for(TypeDesignationBase td : name.getTypeDesignations()){
317
                                if(td.getCitation() == null && isPhycobankID){
318
                                    logger.error("Missing TypeDesignation Citation in Phycobank data");
319
                                    continue;
320
                                }
321
                                if((isPhycobankID && youngestPub == td.getCitation()) || !isPhycobankID){
322
                                    typeDesignations.add(td);
323
                                } else {
324
                                    logger.debug("skipping typedesignation published in older reference");
325
                                }
326
                            }
327
                            reg.setTypeDesignations(typeDesignations);
328
                        }
329
                        reg.setRegistrationDate(regDate);
330
                        logger.debug("IAPT Registration for " + name.getTitleCache());
331
                        newRegs.add(reg);
332

    
333
                    } catch (JsonParseException e) {
334
                        logger.error("Error parsing IAPTRegData from extension", e);
335
                    } catch (JsonMappingException e) {
336
                        logger.error("Error mapping json from extension to IAPTRegData", e);
337
                    } catch (IOException e) {
338
                        logger.error(e);
339
                    }
340

    
341
                }
342
                repo.getRegistrationService().save(newRegs);
343
                repo.getRegistrationService().getSession().flush();
344
                logger.debug("Registrations saved");
345
                pageIndex++;
346
            }
347
            repo.commitTransaction(tx);
348
        }
349
    }
350

    
351

    
352
    /**
353
     * @param datePublished
354
     * @return
355
     */
356
    private Partial partial(TimePeriod datePublished) {
357
        if(datePublished != null){
358
            if(datePublished.getEnd() != null){
359
                return datePublished.getEnd();
360
            } else {
361
                return datePublished.getStart();
362
            }
363
        }
364
        return null;
365
    }
366

    
367

    
368
    /**
369
     * @param office
370
     * @return
371
     */
372
    private Institution getInstitution(String office) {
373
        Institution institution;
374
        if(instituteMap.containsKey(office)){
375
            institution = instituteMap.get(office);
376
        } else {
377

    
378
            Pager<AgentBase> pager = repo.getAgentService().findByTitle(Institution.class, office, MatchMode.EXACT, null, null, null, null, null);
379
            if(!pager.getRecords().isEmpty()){
380
                institution =  (Institution) pager.getRecords().get(0);
381
            } else {
382
                Institution institute = (Institution) repo.getAgentService().save(Institution.NewNamedInstance(office));
383
                institution = institute;
384
            }
385
            instituteMap.put(office, institution);
386
        }
387
        return institution;
388
    }
389

    
390

    
391
    private ExtensionType getExtensionTypeIAPTRegData() {
392
        if(extensionTypeIAPTRegData == null){
393
            extensionTypeIAPTRegData = (ExtensionType) repo.getTermService().load(UUID.fromString("9be1bfe3-6ba0-4560-af15-86971ab96e09"));
394
        }
395
        return extensionTypeIAPTRegData;
396
    }
397

    
398

    
399

    
400
}
(2-2/2)