2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.database
;
12 import java
.util
.HashMap
;
15 import java
.util
.UUID
;
17 import javax
.annotation
.PostConstruct
;
19 import org
.apache
.log4j
.Logger
;
20 import org
.hibernate
.Hibernate
;
21 import org
.joda
.time
.DateTime
;
22 import org
.joda
.time
.Period
;
23 import org
.springframework
.beans
.factory
.annotation
.Autowired
;
24 import org
.springframework
.security
.authentication
.dao
.DaoAuthenticationProvider
;
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
;
31 import eu
.etaxonomy
.cdm
.model
.common
.DefaultTermInitializer
;
32 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
33 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
34 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
35 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
36 import eu
.etaxonomy
.cdm
.model
.common
.VocabularyEnum
;
37 import eu
.etaxonomy
.cdm
.model
.common
.init
.TermLoader
;
38 import eu
.etaxonomy
.cdm
.persistence
.dao
.common
.ITermVocabularyDao
;
41 * Spring bean class to initialize the {@link IVocabularyStore IVocabularyStore}.
42 * To initialize the store the {@link TermLoader TermLoader} and the {@link IVocabularyStore IVocabularyStore}
43 * are injected via spring and the initializeTerms method is called as an init-method (@PostConstruct).
49 public class PersistentTermInitializer
extends DefaultTermInitializer
{
50 private static final Logger logger
= Logger
.getLogger(PersistentTermInitializer
.class);
52 private boolean omit
= false;
53 protected ITermVocabularyDao vocabularyDao
;
55 protected PlatformTransactionManager transactionManager
;
56 protected DefaultTransactionDefinition txDefinition
= new DefaultTransactionDefinition();
58 public PersistentTermInitializer() {
59 txDefinition
.setName("PersistentTermInitializer.initialize()");
60 txDefinition
.setPropagationBehavior(TransactionDefinition
.PROPAGATION_REQUIRED
);
63 public void setOmit(boolean omit
) {
67 public boolean isOmit() {
73 public void setVocabularyDao(ITermVocabularyDao vocabularyDao
) {
74 this.vocabularyDao
= vocabularyDao
;
78 public void setTransactionManager(PlatformTransactionManager transactionManager
) {
79 this.transactionManager
= transactionManager
;
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.
91 public void initialize() {
97 public void doInitialize(){
98 logger
.info("PersistentTermInitializer initialize start ...");
101 logger
.info("PersistentTermInitializer.omit == true, returning without initializing terms");
104 Map
<UUID
,DefinedTermBase
> terms
= new HashMap
<UUID
,DefinedTermBase
>();
105 logger
.info("PersistentTermInitializer.omit == false, initializing " + VocabularyEnum
.values().length
+ " term classes");
107 DateTime start
= new DateTime();
109 TransactionStatus txStatus
= transactionManager
.getTransaction(txDefinition
);
111 //load uuids from csv files
112 logger
.info("Start new ... " );
113 Map
<UUID
, Set
<UUID
>> uuidMap
= new HashMap
<UUID
, Set
<UUID
>>();
114 Map
<UUID
, VocabularyEnum
> vocTypeMap
= new HashMap
<UUID
, VocabularyEnum
>();
116 for(VocabularyEnum vocabularyType
: VocabularyEnum
.values()) {
117 UUID vocUUID
= termLoader
.loadUuids(vocabularyType
, uuidMap
);
118 if (! vocUUID
.equals(vocabularyType
.getUuid())){
119 throw new IllegalStateException("Vocabulary uuid in csv file and vocabulary type differ for vocabulary type " + vocabularyType
.toString());
121 vocTypeMap
.put(vocUUID
, vocabularyType
);
124 //find and create missing terms and load vocabularies from repository
125 logger
.info("Create missing terms ... " );
126 Map
<UUID
, TermVocabulary
<?
>> vocabularyMap
= new HashMap
<UUID
, TermVocabulary
<?
>>();
127 Map
<UUID
, Set
<UUID
>> missingTermUuids
= new HashMap
<UUID
, Set
<UUID
>>();
129 vocabularyDao
.missingTermUuids(uuidMap
, missingTermUuids
, vocabularyMap
);
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 ){
134 VocabularyEnum vocType
= vocTypeMap
.get(vocUuid
); //TODO not really necessary, we could also do VocType.getUuuid();
135 TermVocabulary
<?
> voc
= vocabularyMap
.get(vocUuid
);
137 //vocabulary is missing
138 voc
= termLoader
.loadTerms(vocType
, terms
);
139 vocabularyDao
.save(voc
);
140 vocabularyMap
.put(voc
.getUuid(), voc
);
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
);
148 initializeAndStore(vocabularyType
, terms
, vocabularyMap
); //TODO
151 transactionManager
.commit(txStatus
);
153 DateTime end
= new DateTime();
154 Period period
= new Period(start
, end
);
155 logger
.info ("Term loading took " + period
.getSeconds() + "." + period
.getMillis() + " seconds ");
158 logger
.info("PersistentTermInitializer initialize end ...");
163 * Initializes the static fields of the <code>TermVocabulary</code> classes.
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
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();
175 if (logger
.isDebugEnabled()){ logger
.debug("Loading vocabulary for class " + clazz
.getSimpleName() + " with uuid " + vocabularyUuid
);}
177 TermVocabulary
<?
> persistedVocabulary
;
178 if (vocabularyMap
== null || vocabularyMap
.get(vocabularyUuid
) == null ){
179 persistedVocabulary
= vocabularyDao
.findByUuid(vocabularyUuid
);
181 persistedVocabulary
= vocabularyMap
.get(vocabularyUuid
);
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(Object object
: persistedVocabulary
.getTerms()) {
188 DefinedTermBase
<?
> definedTermBase
= (DefinedTermBase
) object
;
189 Hibernate
.initialize(definedTermBase
.getRepresentations());
190 for(Representation r
: definedTermBase
.getRepresentations()) {
191 Hibernate
.initialize(r
.getLanguage());
193 terms
.put(definedTermBase
.getUuid(), definedTermBase
);
196 logger
.error("Persisted Vocabulary does not exist in database: " + vocabularyUuid
);
197 throw new IllegalStateException("Persisted Vocabulary does not exist in database: " + vocabularyUuid
);
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");}
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.
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
218 public 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
>();
222 for(DefinedTermBase persistedTerm
: persistedTerms
.values()) {
223 terms
.put(persistedTerm
.getUuid(), persistedTerm
);
226 TermVocabulary
<?
> loadedVocabulary
= termLoader
.loadTerms(vocabularyType
, terms
);
228 UUID vocabularyUuid
= loadedVocabulary
.getUuid();
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
);
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
);
247 if(persistedVocabularyHasMissingTerms
) {
248 if (logger
.isDebugEnabled()){logger
.debug("vocabulary " + vocabularyUuid
+ " exists but does not have all the required terms - updating");}
249 updateVocabulary(persistedVocabulary
);
252 return vocabularyUuid
;
255 private void updateVocabulary(TermVocabulary vocabulary
) {
256 TransactionStatus txStatus
= transactionManager
.getTransaction(txDefinition
);
257 vocabularyDao
.update(vocabulary
);
258 transactionManager
.commit(txStatus
);
261 private void saveVocabulary(TermVocabulary vocabulary
) {
262 TransactionStatus txStatus
= transactionManager
.getTransaction(txDefinition
);
263 vocabularyDao
.save(vocabulary
);
264 transactionManager
.commit(txStatus
);