Project

General

Profile

Download (11.5 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

    
10
package eu.etaxonomy.cdm.database;
11

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

    
18
import javax.annotation.PostConstruct;
19

    
20
import org.apache.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

    
47
@Component
48
public class PersistentTermInitializer extends DefaultTermInitializer {
49
    private static final Logger logger = Logger.getLogger(PersistentTermInitializer.class);
50

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

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

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

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

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

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

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

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

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

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

    
106
            DateTime start = new DateTime();
107

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

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

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

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

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

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

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

    
151
            transactionManager.commit(txStatus);
152

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

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

    
161

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

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

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

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

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

    
200

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

    
206
    }
207

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

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

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

    
228
        UUID vocabularyUuid = loadedVocabulary.getUuid();
229

    
230

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

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

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