Project

General

Profile

Download (11.6 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 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.database;
10

    
11
import java.util.HashMap;
12
import java.util.List;
13
import java.util.Map;
14
import java.util.Set;
15
import java.util.UUID;
16

    
17
import javax.annotation.PostConstruct;
18

    
19
import org.apache.logging.log4j.LogManager;
20
import org.apache.logging.log4j.Logger;
21
import org.hibernate.Hibernate;
22
import org.joda.time.DateTime;
23
import org.joda.time.Period;
24
import org.springframework.beans.factory.annotation.Autowired;
25
import org.springframework.stereotype.Component;
26
import org.springframework.transaction.PlatformTransactionManager;
27
import org.springframework.transaction.TransactionDefinition;
28
import org.springframework.transaction.TransactionStatus;
29
import org.springframework.transaction.support.DefaultTransactionDefinition;
30

    
31
import eu.etaxonomy.cdm.model.term.DefaultTermInitializer;
32
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
33
import eu.etaxonomy.cdm.model.term.Representation;
34
import eu.etaxonomy.cdm.model.term.TermVocabulary;
35
import eu.etaxonomy.cdm.model.term.VocabularyEnum;
36
import eu.etaxonomy.cdm.model.term.init.TermLoader;
37
import eu.etaxonomy.cdm.persistence.dao.term.ITermVocabularyDao;
38

    
39
/**
40
 * Spring bean class to initialize the {@link IVocabularyStore IVocabularyStore}.
41
 * To initialize the store the {@link TermLoader TermLoader} and the {@link IVocabularyStore IVocabularyStore}
42
 * are injected via spring and the initializeTerms method is called as an init-method (@PostConstruct).
43
 *
44
 * @author a.mueller
45
 */
46
@Component
47
public class PersistentTermInitializer extends DefaultTermInitializer {
48
    private static final Logger logger = LogManager.getLogger(PersistentTermInitializer.class);
49

    
50
    private boolean omit = false;
51
    protected ITermVocabularyDao vocabularyDao;
52

    
53
    protected PlatformTransactionManager transactionManager;
54
    protected DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
55

    
56
    public PersistentTermInitializer() {
57
        txDefinition.setName("PersistentTermInitializer.initialize()");
58
        txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
59
    }
60

    
61
    @Override
62
    public void setOmit(boolean omit) {
63
        this.omit = omit;
64
    }
65

    
66
    @Override
67
    public boolean isOmit() {
68
        return omit;
69
    }
70

    
71
    @Autowired
72
    public void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
73
        this.vocabularyDao = vocabularyDao;
74
    }
75

    
76
    @Autowired
77
    public void setTransactionManager(PlatformTransactionManager transactionManager) {
78
        this.transactionManager = transactionManager;
79
    }
80

    
81
    /*
82
     * After a bit of head-scratching I found section 3.5.1.3. in the current spring
83
     * reference manual - @PostConstruct / afterPropertiesSet() is called
84
     * immediatly after the bean is constructed, prior to any AOP interceptors being
85
     * wrapped round the bean. Thus, we have to use programmatic transactions, not
86
     * annotations or pointcuts.
87
     */
88
    @PostConstruct
89
    @Override
90
    public void initialize() {
91
        super.initialize();
92
    }
93

    
94
    @Override
95
    public void doInitialize(){
96
        logger.info("PersistentTermInitializer initialize start ...");
97

    
98
        if (omit){
99
            logger.info("PersistentTermInitializer.omit == true, returning without initializing terms");
100
            return;
101
        } else {
102
            Map<UUID,DefinedTermBase> terms = new HashMap<>();
103
            logger.info("PersistentTermInitializer.omit == false, initializing " + VocabularyEnum.values().length + " term classes");
104

    
105
            DateTime start = new DateTime();
106

    
107
            TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
108

    
109
            //load uuids from csv files
110
            logger.info("Start new ... " );
111
            Map<UUID, List<UUID>> uuidMap = new HashMap<>();
112
            Map<UUID, VocabularyEnum> vocTypeMap = new HashMap<>();
113

    
114
            for(VocabularyEnum vocabularyType : VocabularyEnum.values()) {
115
                UUID vocUUID = termLoader.loadUuids(vocabularyType, uuidMap);
116
                if (! vocUUID.equals(vocabularyType.getUuid())){
117
                	throw new IllegalStateException("Vocabulary uuid in csv file and vocabulary type differ for vocabulary type " + vocabularyType.toString());
118
                }
119
                vocTypeMap.put(vocUUID, vocabularyType);
120
            }
121

    
122
            //find and create missing terms and load vocabularies from repository
123
            logger.info("Create missing terms ... " );
124
            Map<UUID, TermVocabulary<?>> vocabularyMap = new HashMap<>();
125
            Map<UUID, Set<UUID>> missingTermUuids = new HashMap<>();
126

    
127
            vocabularyDao.missingTermUuids(uuidMap, missingTermUuids, vocabularyMap);
128

    
129
            for( VocabularyEnum vocabularyType : VocabularyEnum.values()) {   //required to keep the order (language must be the first vocabulary to load)
130
            	UUID vocUuid = vocabularyType.getUuid();
131
            	if (missingTermUuids.keySet().contains(vocabularyType.getUuid()) || vocabularyMap.get(vocUuid) == null ){
132

    
133
            		VocabularyEnum vocType = vocTypeMap.get(vocUuid);  //TODO not really necessary, we could also do VocType.getUuuid();
134
	            	TermVocabulary<?> voc = vocabularyMap.get(vocUuid);
135
	            	if (voc == null){
136
	            		//vocabulary is missing
137
	            		voc = termLoader.loadTerms(vocType, terms);
138
	            		vocabularyDao.save(voc);
139
	            		vocabularyMap.put(voc.getUuid(), voc);
140
	            	}else{
141
	            		//single terms are missing
142
	            		Set<UUID> missingTermsOfVoc = missingTermUuids.get(vocUuid);
143
		            	Set<? extends DefinedTermBase> createdTerms = termLoader.loadSingleTerms(vocType, voc, missingTermsOfVoc);
144
	                	vocabularyDao.saveOrUpdate(voc);
145
	                }
146
	            }
147
	            initializeAndStore(vocabularyType, terms, vocabularyMap);  //TODO
148
        	}
149

    
150
            transactionManager.commit(txStatus);
151

    
152
            DateTime end = new DateTime();
153
            Period period = new Period(start, end);
154
            logger.info ("Term loading took " + period.getSeconds() + "." + period.getMillis() + " seconds ");
155

    
156
        }
157
        logger.info("PersistentTermInitializer initialize end ...");
158
    }
159

    
160

    
161
	/**
162
     * Initializes the static fields of the <code>TermVocabulary</code> classes.
163
     *
164
     * @param clazz the <code>Class</code> of the vocabulary
165
     * @param vocabularyUuid the <code>UUID</code> of the vocabulary
166
     * @param terms a <code>Map</code> containing all already
167
     * 						 loaded terms with their <code>UUID</code> as key
168
     * @param vocabularyMap
169
     */
170
    protected void initializeAndStore(VocabularyEnum vocType, Map<UUID,DefinedTermBase> terms, Map<UUID, TermVocabulary<?>> vocabularyMap) {
171
    	Class<? extends DefinedTermBase<?>> clazz = vocType.getClazz();
172
        UUID vocabularyUuid = vocType.getUuid();
173

    
174
        if (logger.isDebugEnabled()){ logger.debug("Loading vocabulary for class " + clazz.getSimpleName() + " with uuid " + vocabularyUuid );}
175

    
176
        TermVocabulary<? extends DefinedTermBase> persistedVocabulary;
177
        if (vocabularyMap == null || vocabularyMap.get(vocabularyUuid) == null ){
178
        	persistedVocabulary = vocabularyDao.findByUuid(vocabularyUuid);
179
        }else{
180
        	persistedVocabulary = vocabularyMap.get(vocabularyUuid);
181
        }
182

    
183
        if (logger.isDebugEnabled()){ logger.debug("Initializing terms in vocabulary for class " + clazz.getSimpleName() + " with uuid " + vocabularyUuid );}
184
        //not really needed anymore as we do term initializing from the beginning now
185
        if (persistedVocabulary != null){
186
            for(DefinedTermBase<?> definedTermBase : persistedVocabulary.getTerms()) {
187

    
188
            	Hibernate.initialize(definedTermBase.getRepresentations());
189
                for(Representation r : definedTermBase.getRepresentations()) {
190
                    Hibernate.initialize(r.getLanguage());
191
                }
192
                terms.put(definedTermBase.getUuid(), definedTermBase);
193
            }
194
        }else{
195
            logger.error("Persisted Vocabulary does not exist in database: " + vocabularyUuid);
196
            throw new IllegalStateException("Persisted Vocabulary does not exist in database: " + vocabularyUuid);
197
        }
198

    
199

    
200
        //fill term store
201
        if (logger.isDebugEnabled()){ logger.debug("Setting defined Terms for class " + clazz.getSimpleName() + ", " + persistedVocabulary.getTerms().size() + " in vocabulary");}
202
        super.setDefinedTerms(clazz, persistedVocabulary);
203
        if (logger.isDebugEnabled()){ logger.debug("Second pass - DONE");}
204

    
205
    }
206

    
207
    /**
208
     * This method loads the vocabularies from CSV files and compares them to the vocabularies
209
     * already in database. Non-existing vocabularies will be created and vocabularies with missing
210
     * terms will be updated.
211
     *
212
     * @param clazz the <code>Class</code> of the vocabulary
213
     * @param persistedTerms a <code>Map</code> containing all already
214
     * 						 loaded terms with their <code>UUID</code> as key
215
     * @return the <code>UUID</code> of the loaded vocabulary as found in CSV file
216
     */
217
    private UUID firstPass(VocabularyEnum vocabularyType, Map<UUID, DefinedTermBase> persistedTerms) {
218
        logger.info("Loading terms for '" + vocabularyType.name() + "': " + vocabularyType.getClazz().getName());
219
        Map<UUID,DefinedTermBase> terms = new HashMap<UUID,DefinedTermBase>();
220

    
221
        for(DefinedTermBase persistedTerm : persistedTerms.values()) {
222
            terms.put(persistedTerm.getUuid(), persistedTerm);
223
        }
224

    
225
        TermVocabulary<?> loadedVocabulary  = termLoader.loadTerms(vocabularyType, terms);
226

    
227
        UUID vocabularyUuid = loadedVocabulary.getUuid();
228

    
229

    
230
        if (logger.isDebugEnabled()){logger.debug("loading persisted vocabulary " + vocabularyUuid);}
231
        TermVocabulary<DefinedTermBase> persistedVocabulary = vocabularyDao.findByUuid(vocabularyUuid);
232
        if(persistedVocabulary == null) { // i.e. there is no persisted vocabulary
233
            //handle new vocabulary
234
        	if (logger.isDebugEnabled()){logger.debug("vocabulary " + vocabularyUuid + " does not exist - saving");}
235
            saveVocabulary(loadedVocabulary);
236
        }else {
237
        	//handle existing vocabulary
238
            if (logger.isDebugEnabled()){logger.debug("vocabulary " + vocabularyUuid + " does exist and already has " + persistedVocabulary.size() + " terms");}
239
            boolean persistedVocabularyHasMissingTerms = false;
240
            for(Object t : loadedVocabulary.getTerms()) {
241
                if(!persistedVocabulary.getTerms().contains(t)) {
242
                    persistedVocabularyHasMissingTerms = true;
243
                    persistedVocabulary.addTerm((DefinedTermBase)t);
244
                }
245
            }
246
            if(persistedVocabularyHasMissingTerms) {
247
            	if (logger.isDebugEnabled()){logger.debug("vocabulary " + vocabularyUuid + " exists but does not have all the required terms - updating");}
248
                updateVocabulary(persistedVocabulary);
249
            }
250
        }
251
        return vocabularyUuid;
252
    }
253

    
254
    private void updateVocabulary(TermVocabulary vocabulary) {
255
        TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
256
        vocabularyDao.update(vocabulary);
257
        transactionManager.commit(txStatus);
258
    }
259

    
260
    private void saveVocabulary(TermVocabulary vocabulary) {
261
        TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
262
        vocabularyDao.save(vocabulary);
263
        transactionManager.commit(txStatus);
264
    }
265
}
(19-19/21)