reset for defined terms (cont.)
[cdmlib.git] / cdmlib-persistence / src / main / java / eu / etaxonomy / cdm / database / PersistentTermInitializer.java
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.Map;
14 import java.util.UUID;
15
16 import javax.annotation.PostConstruct;
17
18 import org.apache.log4j.Logger;
19 import org.hibernate.Hibernate;
20 import org.springframework.beans.factory.annotation.Autowired;
21 import org.springframework.stereotype.Component;
22 import org.springframework.transaction.PlatformTransactionManager;
23 import org.springframework.transaction.TransactionDefinition;
24 import org.springframework.transaction.TransactionStatus;
25 import org.springframework.transaction.support.DefaultTransactionDefinition;
26
27 import eu.etaxonomy.cdm.model.common.DefaultTermInitializer;
28 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
29 import eu.etaxonomy.cdm.model.common.Representation;
30 import eu.etaxonomy.cdm.model.common.TermVocabulary;
31 import eu.etaxonomy.cdm.model.common.VocabularyEnum;
32 import eu.etaxonomy.cdm.model.common.init.TermLoader;
33 import eu.etaxonomy.cdm.persistence.dao.common.ITermVocabularyDao;
34
35 /**
36 * Spring bean class to initialize the {@link IVocabularyStore IVocabularyStore}.
37 * To initialize the store the {@link TermLoader TermLoader} and the {@link IVocabularyStore IVocabularyStore}
38 * are injected via spring and the initializeTerms method is called as an init-method (@PostConstruct).
39
40 * @author a.mueller
41 */
42
43 @Component
44 public class PersistentTermInitializer extends DefaultTermInitializer {
45 private static final Logger logger = Logger.getLogger(PersistentTermInitializer.class);
46
47 private boolean omit = false;
48 protected ITermVocabularyDao vocabularyDao;
49
50 protected PlatformTransactionManager transactionManager;
51 protected DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition();
52
53 public PersistentTermInitializer() {
54 txDefinition.setName("PersistentTermInitializer.initialize()");
55 txDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
56 }
57
58 public void setOmit(boolean omit) {
59 this.omit = omit;
60 }
61
62 @Autowired
63 public void setVocabularyDao(ITermVocabularyDao vocabularyDao) {
64 this.vocabularyDao = vocabularyDao;
65 }
66
67 @Autowired
68 public void setTransactionManager(PlatformTransactionManager transactionManager) {
69 this.transactionManager = transactionManager;
70 }
71
72 /*
73 * After a bit of head-scratching I found section 3.5.1.3. in the current spring
74 * reference manual - @PostConstruct / afterPropertiesSet() is called
75 * immediatly after the bean is constructed, prior to any AOP interceptors being
76 * wrapped round the bean. Thus, we have to use programmatic transactions, not
77 * annotations or pointcuts.
78 */
79 @PostConstruct
80 @Override
81 public void doInitialize(){
82 logger.debug("PersistentTermInitializer initialize start ...");
83 if (omit){
84 logger.info("PersistentTermInitializer.omit == true, returning without initializing terms");
85 return;
86 } else {
87 Map<UUID,DefinedTermBase> terms = new HashMap<UUID,DefinedTermBase>();
88 logger.info("PersistentTermInitializer.omit == false, initializing " + VocabularyEnum.values().length + " term classes");
89
90 TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
91 for(VocabularyEnum vocabularyType : VocabularyEnum.values()) {
92 //Class<? extends DefinedTermBase<?>> clazz = vocabularyType.getClazz();
93 UUID vocabularyUuid = firstPass(vocabularyType,terms);
94 secondPass(vocabularyType.getClazz(),vocabularyUuid,terms);
95 }
96 transactionManager.commit(txStatus);
97 }
98 logger.debug("PersistentTermInitializer initialize end ...");
99 }
100
101 /**
102 * Initializes the static fields of the <code>TermVocabulary</code> classes.
103 *
104 * @param clazz the <code>Class</code> of the vocabulary
105 * @param vocabularyUuid the <code>UUID</code> of the vocabulary
106 * @param terms a <code>Map</code> containing all already
107 * loaded terms with their <code>UUID</code> as key
108 */
109 protected void secondPass(Class clazz, UUID vocabularyUuid, Map<UUID,DefinedTermBase> terms) {
110 logger.debug("Initializing vocabulary for class " + clazz.getSimpleName() + " with uuid " + vocabularyUuid );
111
112 TermVocabulary persistedVocabulary = vocabularyDao.findByUuid(vocabularyUuid);
113
114 if (persistedVocabulary != null){
115 for(Object object : persistedVocabulary.getTerms()) {
116 DefinedTermBase definedTermBase = (DefinedTermBase) object;
117 Hibernate.initialize(definedTermBase.getRepresentations());
118 for(Representation r : definedTermBase.getRepresentations()) {
119 Hibernate.initialize(r.getLanguage());
120 }
121 terms.put(definedTermBase.getUuid(), definedTermBase);
122 }
123 }else{
124 logger.error("Persisted Vocabulary does not exist in database: " + vocabularyUuid);
125 throw new NullPointerException("Persisted Vocabulary does not exist in database: " + vocabularyUuid);
126 }
127 logger.debug("Setting defined Terms for class " + clazz.getSimpleName());
128 super.setDefinedTerms(clazz, persistedVocabulary);
129 }
130
131 /**
132 * This method loads the vocabularies from CSV files and compares them to the vocabularies
133 * already in database. Non-existing vocabularies will be created and vocabularies with missing
134 * terms will be updated.
135 *
136 * @param clazz the <code>Class</code> of the vocabulary
137 * @param persistedTerms a <code>Map</code> containing all already
138 * loaded terms with their <code>UUID</code> as key
139 * @return the <code>UUID</code> of the loaded vocabulary as found in CSV file
140 */
141 public UUID firstPass(VocabularyEnum vocabularyType, Map<UUID, DefinedTermBase> persistedTerms) {
142 logger.debug("loading terms for " + vocabularyType.getClazz().getSimpleName());
143 Map<UUID,DefinedTermBase> terms = new HashMap<UUID,DefinedTermBase>();
144
145 for(DefinedTermBase d : persistedTerms.values()) {
146 terms.put(d.getUuid(), d);
147 }
148
149 TermVocabulary loadedVocabulary = termLoader.loadTerms(vocabularyType, terms);
150
151 UUID vocabularyUuid = loadedVocabulary.getUuid();
152
153
154 logger.debug("loading vocabulary " + vocabularyUuid);
155 TermVocabulary persistedVocabulary = vocabularyDao.findByUuid(vocabularyUuid);
156 if(persistedVocabulary == null) { // i.e. there is no persisted vocabulary
157 logger.debug("vocabulary " + vocabularyUuid + " does not exist - saving");
158 saveVocabulary(loadedVocabulary);
159 }else {
160 logger.debug("vocabulary " + vocabularyUuid + " does exist and already has " + persistedVocabulary.size() + " terms");
161 boolean persistedVocabularyHasMissingTerms = false;
162 for(Object t : loadedVocabulary.getTerms()) {
163 if(!persistedVocabulary.getTerms().contains(t)) {
164 persistedVocabularyHasMissingTerms = true;
165 persistedVocabulary.addTerm((DefinedTermBase)t);
166 }
167 }
168 if(persistedVocabularyHasMissingTerms) {
169 logger.debug("vocabulary " + vocabularyUuid + " exists but does not have all the required terms - updating");
170 updateVocabulary(persistedVocabulary);
171 }
172 }
173 return vocabularyUuid;
174 }
175
176 private void updateVocabulary(TermVocabulary vocabulary) {
177 TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
178 vocabularyDao.update(vocabulary);
179 transactionManager.commit(txStatus);
180 }
181
182 private void saveVocabulary(TermVocabulary vocabulary) {
183 TransactionStatus txStatus = transactionManager.getTransaction(txDefinition);
184 vocabularyDao.save(vocabulary);
185 transactionManager.commit(txStatus);
186 }
187 }