ref #6794 fix early setting of termType during term loading
[cdmlib.git] / cdmlib-model / src / main / java / eu / etaxonomy / cdm / model / common / init / TermLoader.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.model.common.init;
11
12 import java.io.IOException;
13 import java.lang.reflect.Constructor;
14 import java.util.ArrayList;
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.springframework.stereotype.Component;
24
25 import au.com.bytecode.opencsv.CSVReader;
26 import eu.etaxonomy.cdm.common.CdmUtils;
27 import eu.etaxonomy.cdm.model.common.DefinedTermBase;
28 import eu.etaxonomy.cdm.model.common.OrderedTermBase;
29 import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;
30 import eu.etaxonomy.cdm.model.common.TermType;
31 import eu.etaxonomy.cdm.model.common.TermVocabulary;
32 import eu.etaxonomy.cdm.model.common.VocabularyEnum;
33
34 @Component
35 public class TermLoader implements ITermLoader {
36 private static final Logger logger = Logger.getLogger(TermLoader.class);
37
38 @Override
39 public void unloadAllTerms(){
40 for(VocabularyEnum vocabularyEnum : VocabularyEnum.values()) {
41 // Class<? extends DefinedTermBase<?>> clazz = vocabularyEnum.getClazz();
42 this.unloadVocabularyType(vocabularyEnum);
43 }
44 }
45
46 private <T extends DefinedTermBase> void unloadVocabularyType(VocabularyEnum vocType){
47 Class<? extends DefinedTermBase> termClass = vocType.getClazz();
48 getInstance(termClass).resetTerms();
49 return;
50 }
51
52 @Override
53 public UUID loadUuids(VocabularyEnum vocType, Map<UUID, Set<UUID>> uuidMap) {
54
55 try {
56 CSVReader reader = getCsvReader(vocType);
57 String[] nextLine = reader.readNext();
58 UUID uuidVocabulary = UUID.fromString(nextLine[0]);
59 Set<UUID> termSet = new HashSet<>();
60 uuidMap.put(uuidVocabulary, termSet);
61
62 while ( (nextLine = reader.readNext()) != null) {
63 UUID uuidTerm = UUID.fromString(nextLine[0]);
64 termSet.add(uuidTerm);
65 }
66 return uuidVocabulary;
67
68
69 } catch (Exception e) {
70 logger.error(e + " " + e.getCause() + " " + e.getMessage());
71 for(StackTraceElement ste : e.getStackTrace()) {
72 logger.error(ste);
73 }
74 throw new RuntimeException(e);
75 }
76
77 }
78
79 @Override
80 public <T extends DefinedTermBase> TermVocabulary<T> loadTerms(VocabularyEnum vocType, Map<UUID,DefinedTermBase> terms) {
81
82
83 try {
84 CSVReader reader = getCsvReader(vocType);
85
86 String [] nextLine = reader.readNext();
87
88
89 Class<? extends DefinedTermBase> termClass = vocType.getClazz();
90
91 //vocabulary
92 TermVocabulary<T> voc;
93 TermType termType = TermType.Unknown;
94 if (OrderedTermBase.class.isAssignableFrom(termClass)){
95 voc = OrderedTermVocabulary.NewInstance(termType);
96 }else{
97 voc = TermVocabulary.NewInstance(termType);
98 }
99
100 if (nextLine != null){
101 voc.readCsvLine(arrayedLine(nextLine));
102 }
103 termType = voc.getTermType();
104 boolean abbrevAsId = (arrayedLine(nextLine).get(5).equals("1"));
105
106 // Ugly, I know, but I don't think we can use a static method here . .
107
108 T classDefiningTermInstance = getInstance(termClass);// ((Class<T>)termClass).newInstance();
109
110 while ((nextLine = reader.readNext()) != null) {
111 // nextLine[] is an array of values from the line
112 if (nextLine.length == 0){
113 continue;
114 }
115
116 handleSingleTerm(nextLine, terms, termClass, voc,
117 abbrevAsId, classDefiningTermInstance);
118
119 }
120 return voc;
121 } catch (Exception e) {
122 logger.error(e + " " + e.getCause() + " " + e.getMessage());
123 for(StackTraceElement ste : e.getStackTrace()) {
124 logger.error(ste);
125 }
126 throw new RuntimeException(e);
127 }
128
129 }
130
131 /**
132 * Handles a single csv line, creates the term and adds it to the vocabulary and to the terms map.
133 * @param csvLine csv line
134 * @param terms UUID-Term map this term should be added to
135 * @param termClass the class of the term to create
136 * @param voc the vocabulary the term should be added to
137 * @param abbrevAsId boolean value, if true the abbreviation should be taken as idInVocabulary
138 * @param classDefiningTermInstance instance for calling readCsvLine
139 * @return
140 */
141 private <T extends DefinedTermBase> T handleSingleTerm(String[] csvLine, Map<UUID,DefinedTermBase> terms,
142 Class<? extends DefinedTermBase> termClass,
143 TermVocabulary<T> voc, boolean abbrevAsId,
144 T classDefiningTermInstance) {
145 T term = (T) classDefiningTermInstance.readCsvLine(termClass,arrayedLine(csvLine), voc.getTermType(), terms, abbrevAsId);
146 voc.addTerm(term);
147 terms.put(term.getUuid(), term);
148 return term;
149 }
150
151
152 @Override
153 public <T extends DefinedTermBase> Set<T> loadSingleTerms(VocabularyEnum vocType,
154 TermVocabulary<T> voc, Set<UUID> missingTerms) {
155 try {
156 Class<? extends DefinedTermBase> termClass = vocType.getClazz();
157
158 CSVReader reader = getCsvReader(vocType);
159 String [] nextLine = reader.readNext();
160
161 if (! UUID.fromString(nextLine[0]).equals(voc.getUuid())){
162 throw new IllegalStateException("Vocabularies in csv file and vocabulary must be equal");
163 }
164
165
166
167 boolean abbrevAsId = (arrayedLine(nextLine).get(5).equals("1"));
168 T classDefiningTermInstance = getInstance(termClass);// ((Class<T>)termClass).newInstance();
169 Map<UUID,DefinedTermBase> allVocTerms = new HashMap<UUID, DefinedTermBase>();
170 for (T term:voc.getTerms()){
171 allVocTerms.put(term.getUuid(), term);
172 }
173
174 while ((nextLine = reader.readNext()) != null) {
175 if (nextLine.length == 0){
176 continue;
177 }
178 UUID uuid = UUID.fromString(nextLine[0]);
179 if (missingTerms.contains(uuid)){
180 handleSingleTerm(nextLine, allVocTerms, termClass, voc, abbrevAsId, classDefiningTermInstance);
181 }
182 }
183
184 return null;
185 } catch (Exception e) {
186 e.printStackTrace();
187 throw new RuntimeException(e);
188 }
189 }
190
191 /**
192 * Returns the {@link CSVReader} for the given {@link VocabularyEnum}.
193 * @param vocType
194 * @return
195 * @throws IOException
196 */
197 private CSVReader getCsvReader(VocabularyEnum vocType) throws IOException {
198 String filename = vocType.name()+".csv";
199 String strResourceFileName = "terms" + CdmUtils.getFolderSeperator() + filename;
200 if (logger.isDebugEnabled()){logger.debug("strResourceFileName is " + strResourceFileName);}
201 CSVReader reader = new CSVReader(CdmUtils.getUtf8ResourceReader(strResourceFileName));
202 return reader;
203 }
204
205 /**
206 * Returns a new instance for the given class by using the default constructor.
207 * The constructor must be declared but can be unaccessible (e.g. private)
208 * @param termClass
209 * @return
210 */
211 private <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass) {
212 try {
213 Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
214 c.setAccessible(true);
215 T termInstance = c.newInstance();
216 return termInstance;
217 } catch (Exception e) {
218 throw new RuntimeException(e);
219 }
220 }
221
222 private List<String> arrayedLine(String [] nextLine){
223 ArrayList<String> csvTermAttributeList = new ArrayList<String>(15);
224 for (String col : nextLine){
225 csvTermAttributeList.add(col);
226 }
227 while (csvTermAttributeList.size()<15){
228 csvTermAttributeList.add("");
229 }
230 return csvTermAttributeList;
231 }
232
233 }