View Javadoc
1   /*******************************************************************************
2    *   Gisgraphy Project 
3    * 
4    *   This library is free software; you can redistribute it and/or
5    *   modify it under the terms of the GNU Lesser General Public
6    *   License as published by the Free Software Foundation; either
7    *   version 2.1 of the License, or (at your option) any later version.
8    * 
9    *   This library is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   *   Lesser General Public License for more details.
13   * 
14   *   You should have received a copy of the GNU Lesser General Public
15   *   License along with this library; if not, write to the Free Software
16   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
17   * 
18   *  Copyright 2008  Gisgraphy project 
19   *  David Masclet <davidmasclet@gisgraphy.com>
20   *  
21   *  
22   *******************************************************************************/
23  package com.gisgraphy.importer;
24  
25  import java.io.File;
26  import java.text.ParseException;
27  import java.text.SimpleDateFormat;
28  import java.util.ArrayList;
29  import java.util.List;
30  import java.util.regex.Matcher;
31  import java.util.regex.Pattern;
32  
33  import org.hibernate.FlushMode;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  import org.springframework.beans.factory.annotation.Autowired;
37  import org.springframework.beans.factory.annotation.Required;
38  
39  import com.gisgraphy.domain.geoloc.entity.Adm;
40  import com.gisgraphy.domain.geoloc.entity.AlternateName;
41  import com.gisgraphy.domain.geoloc.entity.City;
42  import com.gisgraphy.domain.geoloc.entity.CitySubdivision;
43  import com.gisgraphy.domain.geoloc.entity.Country;
44  import com.gisgraphy.domain.geoloc.entity.GisFeature;
45  import com.gisgraphy.domain.geoloc.entity.ZipCode;
46  import com.gisgraphy.domain.repository.IAdmDao;
47  import com.gisgraphy.domain.repository.IAlternateNameDao;
48  import com.gisgraphy.domain.repository.ICityDao;
49  import com.gisgraphy.domain.repository.ICountryDao;
50  import com.gisgraphy.domain.repository.IGisDao;
51  import com.gisgraphy.domain.repository.IGisFeatureDao;
52  import com.gisgraphy.domain.repository.ISolRSynchroniser;
53  import com.gisgraphy.domain.valueobject.AlternateNameSource;
54  import com.gisgraphy.domain.valueobject.Constants;
55  import com.gisgraphy.domain.valueobject.FeatureCode;
56  import com.gisgraphy.domain.valueobject.GISSource;
57  import com.gisgraphy.domain.valueobject.NameValueDTO;
58  import com.gisgraphy.helper.FeatureClassCodeHelper;
59  import com.gisgraphy.helper.GeolocHelper;
60  import com.gisgraphy.util.StringUtil;
61  
62  /**
63   * Import the Features from a Geonames dump file.
64   * 
65   * @author <a href="mailto:david.masclet@gisgraphy.com">David Masclet</a>
66   */
67  public class GeonamesFeatureSimpleImporter extends AbstractSimpleImporterProcessor {
68  
69  	protected static final Logger logger = LoggerFactory.getLogger(GeonamesFeatureSimpleImporter.class);
70  	
71      protected ICityDao cityDao;
72  
73      protected IGisFeatureDao gisFeatureDao;
74  
75      protected IAlternateNameDao alternateNameDao;
76  
77      protected IAdmDao admDao;
78  
79    
80      protected ICountryDao countryDao;
81  
82      protected Pattern acceptedPatterns ;
83      
84  
85      protected ISolRSynchroniser solRSynchroniser;
86  
87      @Autowired
88      protected IGisDao<? extends GisFeature>[] iDaos;
89      
90      @Autowired
91      protected IMunicipalityDetector municipalityDetector;
92      
93  
94      /**
95       * Default constructor
96       */
97      public GeonamesFeatureSimpleImporter() {
98  	super();
99      }
100 
101     private SimpleDateFormat dateFormatter = new SimpleDateFormat(
102 	    Constants.GIS_DATE_PATTERN);
103 
104     boolean isPlaceTypeAccepted(String classname) {
105 	if (acceptedPatterns.matcher(classname).find()){
106 		return true;
107 	}
108 	return false;
109     }
110 
111     /*
112      * (non-Javadoc)
113      * 
114      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#processData(java.lang.String)
115      */
116     @Override
117     protected void processData(String line) {
118 	String[] fields = line.split("\t");
119 
120 	/*
121 	 * line table has the following fields :
122 	 * --------------------------------------------------- 0 geonameid : 1
123 	 * name 2 asciiname 3 alternatenames 4 latitude 5 longitude 6 feature
124 	 * class 7 feature code 8 country code 9 cc2 10 admin1 code 11 admin2
125 	 * code 12 admin3 code 13 admin4 code 14 population 15 elevation 16
126 	 * gtopo30 17 timezone 18 modification date last modification in
127 	 * yyyy-MM-dd format
128 	 */
129 
130 	// check that the csv file line is in a correct format
131 	checkNumberOfColumn(fields);
132 	String featureClass = null;
133 	String featureCode = null;
134 
135 	// featureClass
136 	if (!isEmptyField(fields, 6, false)) {
137 	    featureClass = fields[6];
138 	} else {
139 	    featureClass = ImporterConfig.DEFAULT_FEATURE_CLASS;
140 	    logger.warn("[wrongFeatureClass] : set featureClass to "
141 		    + ImporterConfig.DEFAULT_FEATURE_CODE + " for gisFeature  "
142 		    + fields[0]);
143 	}
144 
145 	// featureCode
146 	if (!isEmptyField(fields, 7, false)) {
147 	    featureCode = fields[7];
148 	} else {
149 	    featureCode = ImporterConfig.DEFAULT_FEATURE_CODE;
150 	    logger.warn("[wrongFeatureCode] set featureCode to "
151 		    + ImporterConfig.DEFAULT_FEATURE_CODE + " for gisFeature  "
152 		    + fields[0]);
153 	}
154 
155 	if (FeatureClassCodeHelper.is_Adm(featureClass,featureCode) && !isAdmMode()){
156 	    return;
157 	}
158 	// TODO v2 virtualizeADMD
159 	// fields = ImporterHelper.virtualizeADMD(fields);
160 	fields = ImporterHelper.correctLastAdmCodeIfPossible(fields);
161 
162 	FeatureCode featureCode_ = null;
163 
164 	try {
165 	    featureCode_ = FeatureCode
166 		    .valueOf(featureClass + "_" + featureCode);
167 	} catch (RuntimeException e) {
168 	}
169 	GisFeature gisFeature = null;
170 	String name = fields[1];
171 	if (name.length() > GisFeature.NAME_MAX_LENGTH){
172 		logger.warn(name + "is too long");
173 		return;
174 	}
175 	if (featureCode_ != null ) {
176 		gisFeature = (GisFeature) featureCode_.getObject();
177 		gisFeature = correctPlaceType(gisFeature, name);
178 	    if (gisFeature!=null && !isPlaceTypeAccepted(gisFeature.getClass().getSimpleName())){
179 	    	return;
180 	    }
181 	} else {
182 		gisFeature = new GisFeature();
183 	}
184 	
185 
186 	
187 	// create GisFeature and set featureId
188 	if (!isEmptyField(fields, 0, true)) {
189 	   // gisFeature = new GisFeature();
190 	    gisFeature.setFeatureId(new Long(fields[0]));
191 	}
192 
193 	// set names
194 	if (!isEmptyField(fields, 1, true)) {
195 	    gisFeature.setName(name.trim());
196 	}
197 
198 	gisFeature.setAsciiName(fields[2].trim());
199 
200 	// Location
201 	if (!isEmptyField(fields, 4, true) && !isEmptyField(fields, 5, true)) {
202 	    gisFeature.setLocation(GeolocHelper.createPoint(
203 		    new Float(fields[5]), new Float(fields[4])));
204 	}
205 
206 	// featureClass
207 	gisFeature.setFeatureClass(featureClass);
208 
209 	// featureCode
210 	gisFeature.setFeatureCode(featureCode);
211 	
212 
213 	// countrycode
214 	if (!isEmptyField(fields, 8, true)) {
215 	    gisFeature.setCountryCode(fields[8].toUpperCase());
216 	}
217 
218 	// ignore cc2
219 
220 	// population
221 	if (!isEmptyField(fields, 14, false)) {
222 	    gisFeature.setPopulation(new Integer(fields[14]));
223 	}
224 
225 	// elevation
226 	if (!isEmptyField(fields, 15, false)) {
227 	    gisFeature.setElevation(new Integer(fields[15]));
228 	} else {
229 	    gisFeature.setElevation(null);
230 	}
231 
232 	// gtopo30
233 	if (!isEmptyField(fields, 16, false)) {
234 	    gisFeature.setGtopo30(new Integer(fields[16]));
235 	}
236 
237 	// timeZone
238 	gisFeature.setTimezone(fields[17]);
239 
240 	// source
241 	gisFeature.setSource(GISSource.GEONAMES);
242 
243 	// modificationDate
244 	if (!isEmptyField(fields, 18, false)) {
245 	    try {
246 		gisFeature.setModificationDate(dateFormatter.parse(fields[18]));
247 	    } catch (ParseException e) {
248 		gisFeature.setModificationDate(null);
249 		logger
250 			.info("[wrongModificationDate] Modificationdate is not properly set for featureId "
251 				+ fields[0]);
252 	    }
253 	}
254 
255 	// add alternatenames
256 	// not necessary because alternatenames will be added by its own
257 	// importer
258 	if (!isEmptyField(fields, 3, false)
259 		&& importerConfig.isImportGisFeatureEmbededAlternateNames()) {
260 	    List<AlternateName> splitedAlternateNames = splitAlternateNames(fields[3],
261 		    gisFeature);
262 		gisFeature.addAlternateNames(splitedAlternateNames);
263 	}
264 
265 	//TODO  //NAI list countryid
266 	Country country = this.countryDao.getByFeatureId(new Long(fields[0]));
267 
268 	if (country != null) {
269 	    String countryName = country.getName();
270 	    country.populate(gisFeature);
271 	    // we preffer keep the original name (example : we prefer
272 	    // France,
273 	    // instead of Republic Of France
274 	    country.setName(countryName);
275 	    this.countryDao.save(country);
276 	    return;
277 	}
278 
279 	
280 	if (featureCode_ != null) {
281 	    if (featureCode_.getObject() instanceof Country) {
282 		logger.warn("[wrongCountryCode] Country " + fields[8]
283 			+ " have no entry in "
284 			+ importerConfig.getCountriesFileName()
285 			+ " or has not been imported. It will be ignored");
286 		return;
287 
288 	    }
289 	}
290 
291 	// Rem :if we don't set the code they will be null for object that
292 	// extends gisfeature when populate() will be called
293 	// Rem : country don't have their admXcodes and AdmXnames
294 	// set admcodes
295 	setAdmCodesWithCSVOnes(fields, gisFeature);
296 
297 	// if gis Feature is an ADM need to update ADM with this GisFeature
298 		if (gisFeature.isAdm()) {
299 			if (isAdmMode()) {
300 				Adm adm = processAdm(fields, gisFeature);
301 				if (adm != null) {
302 					this.admDao.save(adm);
303 				}
304 				return;
305 			} else {
306 				// it is an adm that must be treated in adm importer
307 				return;
308 			}
309 		}
310 
311 	// it is not an adm, not a country =>try to set Adm
312 	Adm adm = null;
313 	if (importerConfig.isTryToDetectAdmIfNotFound()) {
314 	    adm = this.admDao.suggestMostAccurateAdm(fields[8], fields[10],
315 		    fields[11], fields[12], fields[13], gisFeature);
316 	    logger.debug("suggestAdm=" + adm);
317 	} else {
318 	    adm = this.admDao.getAdm(fields[8], fields[10], fields[11],
319 		    fields[12], fields[13]);
320 	}
321 
322 	// log
323 	if (adm == null) {
324 	    logger.warn("[noAdm] " + fields[8] + "." + fields[10] + "."
325 		    + fields[11] + "." + fields[12] + "." + fields[13]
326 		    + " for " + gisFeature);
327 	} else {
328 	    if ("00".equals(fields[10]) && !featureCode.startsWith("ADM")) {
329 		logger
330 			.info("[adm1autoDetected];" + gisFeature.getFeatureId()
331 				+ ";" + gisFeature.getName() + ";"
332 				+ gisFeature.getFeatureClass() + ";"
333 				+ gisFeature.getFeatureCode() + ";"
334 				+ adm.getAdm1Code());
335 		// see http://forum.geonames.org/gforum/posts/list/699.page
336 	    }
337 
338 	}
339 	gisFeature.setAdm(adm);
340 	setAdmCodesWithLinkedAdmOnes(adm, gisFeature, importerConfig
341 		.isSyncAdmCodesWithLinkedAdmOnes());
342 	setAdmNames(adm, gisFeature);
343 
344 	if (featureCode_ != null) {
345 	   if (gisFeature instanceof City){
346 	    	((City)gisFeature).setMunicipality(municipalityDetector.isMunicipality(fields[8].toUpperCase(),null,null,GISSource.GEONAMES));
347 	    }
348 	    
349 		// zipcode
350 	   
351 		String foundZipCode = findZipCode(fields);
352 		if (foundZipCode != null){
353 			gisFeature.addZipCode(new ZipCode(foundZipCode));//TODO tests zip we should take embeded option into account
354 		}
355 	    this.gisFeatureDao.save(gisFeature);
356 	} else {
357 	    logger.debug(featureClass + "_" + featureCode
358 		    + " have no entry in " + FeatureCode.class.getSimpleName()
359 		    + " and will be considered as a GisFeature");
360 	    this.gisFeatureDao.save(gisFeature);
361 	}
362 	// }
363 
364     }
365 
366 	protected GisFeature correctPlaceType(GisFeature featureObject, String name) {
367 		if (StringUtil.containsDigit(name) && featureObject!=null && featureObject!=null && featureObject.getClass()==City.class){
368 	    	featureObject= new CitySubdivision();
369 	    }
370 		return featureObject;
371 	}
372     
373     protected boolean isAdmMode() {
374         return false;
375     }
376 
377     protected Adm processAdm(String[] fields, GisFeature gisFeature) {
378 	int levelFromCode = Adm.getProcessedLevelFromCodes(fields[10],
379 	    fields[11], fields[12], fields[13]);
380 	int levelFromClassCode = Adm.getProcessedLevelFromFeatureClassCode(
381 	    fields[6], fields[7]);
382 	// check if data are consistant
383 	if (levelFromCode != levelFromClassCode) {
384 	logger.warn("[unprocessed Adm] : The Adm " + fields[8] + "."
385 		+ fields[10] + "." + fields[11] + "." + fields[12]
386 		+ "." + fields[13] + " is not consistant for "
387 		+ fields[6] + "." + fields[7] + " adm" + "["
388 		+ fields[0] + "] will be ignored");
389 	return null;
390 	}
391 	Adm adm = this.admDao.getAdm(fields[8], fields[10], fields[11],
392 	    fields[12], fields[13]);
393 	if (adm != null) {
394 		logger
395 		.warn("[unprocessed Adm] : "+
396 			gisFeature+ " will not be saved because it is duplicate (same codes) with "
397 			+ adm);	
398 		return null;
399 	}
400 
401 	if (levelFromCode != 0) {
402 	    adm = new Adm(levelFromCode);
403 	    //adm.setName(fields[1].trim());
404 	    adm.setAdm1Name(fields[10]);
405 	    adm.setAdm2Name(fields[11]);
406 	    adm.setAdm3Name(fields[12]);
407 	    adm.setAdm4Name(fields[13]);
408 	    // the only goal to do this code is to get the adm codes in
409 	    // the
410 	    // logs bellow when toString will be called (in other way it
411 	    // will be done by the populate)
412 	    setAdmCodesWithCSVOnes(fields, adm);
413 	    // try to link to his parent
414 	    if (levelFromCode>1){
415 	    Adm admParent = this.admDao
416 		    .getAdmOrFirstValidParentIfNotFound(fields[8],
417 			    fields[10], fields[11], fields[12],
418 			    fields[13]);
419 	    if (admParent != null) {
420 	    	adm.setParent(admParent);
421 	    } else {
422 		logger
423 			.warn("[unprocessed Adm] : won't save an adm"
424 				+ levelFromCode
425 				+ " : "
426 				+ adm
427 				+ " that have not been import when AdmXCodes and without parent");
428 		return null;
429 	    }
430 	    }
431 	} else {
432 	    // we can do anything with an Adm with Wrong code/level
433 	    logger
434 		    .warn("[unprocessedAdm] : Could not detect level of Adm "
435 			    + adm + ". it will be ignored");
436 	    return null;
437 	}
438 	if (isAlreadyUpdated(adm)) {// needed for duplicate
439 	// we only keep the first adm
440 	return null;
441 	}
442 	setAdmNames(adm, gisFeature);
443 	adm.populate(gisFeature);
444 	return adm;
445     }
446     
447     /* (non-Javadoc)
448      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#shouldBeSkiped()
449      */
450     @Override
451     public boolean shouldBeSkipped() {
452 	return !importerConfig.isGeonamesImporterEnabled();
453     }
454 
455     private boolean isAlreadyUpdated(GisFeature feature) {
456 	if (feature.getModificationDate() != null) {
457 	    logger
458 		    .info(feature
459 			    + " has already been updated, it is probably a duplicate entry");
460 	    return true;
461 	}
462 	return false;
463     }
464 
465     private void setAdmNames(Adm adm, GisFeature gisFeature) {
466 	if (adm == null) {
467 	    return;
468 	}
469 	Adm admTemp = adm;
470 	do {
471 	    if (admTemp.getLevel() == 1) {
472 		gisFeature.setAdm1Name(admTemp.getName());
473 	    } else if (admTemp.getLevel() == 2) {
474 		gisFeature.setAdm2Name(admTemp.getName());
475 	    } else if (admTemp.getLevel() == 3) {
476 		gisFeature.setAdm3Name(admTemp.getName());
477 	    } else if (admTemp.getLevel() == 4) {
478 		gisFeature.setAdm4Name(admTemp.getName());
479 	    }
480 	    admTemp = admTemp.getParent();
481 	} while (admTemp != null);
482 
483     }
484 
485     private void setAdmCodesWithLinkedAdmOnes(Adm adm, GisFeature gisFeature,
486 	    boolean syncAdmCodesWithLinkedAdmOnes) {
487 
488 	if (syncAdmCodesWithLinkedAdmOnes) {
489 	    // reset adm code because we might link to an adm3 and adm4 code
490 	    // have
491 	    // been set
492 	    setAdmCodesToNull(gisFeature);
493 	    if (adm != null) {
494 		if (adm.getAdm1Code() != null) {
495 		    gisFeature.setAdm1Code(adm.getAdm1Code());
496 		}
497 		if (adm.getAdm2Code() != null) {
498 		    gisFeature.setAdm2Code(adm.getAdm2Code());
499 		}
500 		if (adm.getAdm3Code() != null) {
501 		    gisFeature.setAdm3Code(adm.getAdm3Code());
502 		}
503 		if (adm.getAdm4Code() != null) {
504 		    gisFeature.setAdm4Code(adm.getAdm4Code());
505 		}
506 	    }
507 
508 	}
509     }
510 
511     private void setAdmCodesToNull(GisFeature gisFeature) {
512 	gisFeature.setAdm1Code(null);
513 	gisFeature.setAdm2Code(null);
514 	gisFeature.setAdm3Code(null);
515 	gisFeature.setAdm4Code(null);
516     }
517 
518     private void setAdmCodesWithCSVOnes(String[] fields, GisFeature gisFeature) {
519 	logger.debug("in setAdmCodesWithCSVOnes");
520 	if (!isEmptyField(fields, 10, false)) {
521 	    gisFeature.setAdm1Code(fields[10]);
522 	}
523 	if (!isEmptyField(fields, 11, false)) {
524 	    gisFeature.setAdm2Code(fields[11]);
525 	}
526 	if (!isEmptyField(fields, 12, false)) {
527 	    gisFeature.setAdm3Code(fields[12]);
528 	}
529 	if (!isEmptyField(fields, 13, false)) {
530 	    gisFeature.setAdm4Code(fields[13]);
531 	}
532     }
533 
534     
535     
536     private List<AlternateName> splitAlternateNames(String alternateNamesString,
537 	    GisFeature gisFeature) {
538 	String[] alternateNames = alternateNamesString.split(",");
539 	List<AlternateName> alternateNamesList = new ArrayList<AlternateName>();
540 	for (String name : alternateNames) {
541 	    AlternateName alternateName = new AlternateName();
542 	    alternateName.setName(name.trim());
543 	    alternateName.setSource(AlternateNameSource.EMBEDED);
544 	    alternateName.setGisFeature(gisFeature);
545 	    alternateNamesList.add(alternateName);
546 	}
547 	return alternateNamesList;
548     }
549 
550     private String findZipCode(String[] fields) {
551 	logger.debug("try to detect zipCode for " + fields[1] + "[" + fields[0]
552 		+ "]");
553 	String zipCode = null;
554 	String[] alternateNames = fields[3].split(",");
555 	boolean found = false;
556 	Pattern patterncountry = null;
557 	Matcher matcherCountry = null;
558 	if (!isEmptyField(fields, 8, false)) {
559 	    Country country = countryDao.getByIso3166Alpha2Code(fields[8]);
560 	    if (country != null) {
561 		String regex = country.getPostalCodeRegex();
562 		if (regex != null) {
563 		    patterncountry = Pattern.compile(regex);
564 		    if (patterncountry == null) {
565 			logger.info("can not compile regexp" + regex);
566 			return null;
567 		    }
568 		} else {
569 		    logger.debug("regex=null for country " + country);
570 		    return null;
571 		}
572 	    } else {
573 		logger
574 			.warn("can not proces ZipCode because can not find country for "
575 				+ fields[8]);
576 		return null;
577 	    }
578 
579 	} else {
580 	    logger.warn("can not proces ZipCode because can not find country ");
581 	}
582 	for (String element : alternateNames) {
583 	    matcherCountry = patterncountry.matcher(element);
584 	    if (matcherCountry.matches()) {
585 		if (found) {
586 		    logger
587 			    .info("There is more than one possible ZipCode for feature with featureid="
588 				    + fields[0] + ". it will be ignore");
589 		    return null;
590 		}
591 		try {
592 		    zipCode = element;
593 		    found = true;
594 		} catch (NumberFormatException e) {
595 		}
596 
597 	    }
598 	}
599 	logger.debug("found " + zipCode + " for " + fields[1] + "[" + fields[0]
600 		+ "]");
601 	return zipCode;
602     }
603 
604     /*
605      * (non-Javadoc)
606      * 
607      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#shouldIgnoreFirstLine()
608      */
609     @Override
610     protected boolean shouldIgnoreFirstLine() {
611 	return false;
612     }
613 
614     /*
615      * (non-Javadoc)
616      * 
617      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#shouldIgnoreComments()
618      */
619     @Override
620     protected boolean shouldIgnoreComments() {
621 	return true;
622     }
623 
624     /*
625      * (non-Javadoc)
626      * 
627      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#setCommitFlushMode()
628      */
629     @Override
630     protected void setCommitFlushMode() {
631     	this.cityDao.setFlushMode(FlushMode.COMMIT);
632     	this.gisFeatureDao.setFlushMode(FlushMode.COMMIT);
633     	this.alternateNameDao.setFlushMode(FlushMode.COMMIT);
634     	this.admDao.setFlushMode(FlushMode.COMMIT);
635     }
636 
637     /*
638      * (non-Javadoc)
639      * 
640      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#flushAndClear()
641      */
642     @Override
643     protected void flushAndClear() {
644     	this.cityDao.flushAndClear();
645     	this.gisFeatureDao.flushAndClear();
646     	this.alternateNameDao.flushAndClear();
647     	this.admDao.flushAndClear();
648     }
649 
650     /*
651      * (non-Javadoc)
652      * 
653      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#getNumberOfColumns()
654      */
655     @Override
656     protected int getNumberOfColumns() {
657 	return 19;
658     }
659 
660     /**
661      * @param cityDao
662      *                The CityDao to set
663      */
664     @Required
665     public void setCityDao(ICityDao cityDao) {
666 	this.cityDao = cityDao;
667     }
668 
669     /**
670      * @param alternateNameDao
671      *                The alternateNameDao to set
672      */
673     @Required
674     public void setAlternateNameDao(IAlternateNameDao alternateNameDao) {
675 	this.alternateNameDao = alternateNameDao;
676     }
677 
678     /**
679      * @param gisFeatureDao
680      *                The GisFeatureDao to set
681      */
682     @Required
683     public void setGisFeatureDao(IGisFeatureDao gisFeatureDao) {
684 	this.gisFeatureDao = gisFeatureDao;
685     }
686 
687     /**
688      * @param admDao
689      *                the admDao to set
690      */
691     @Required
692     public void setAdmDao(IAdmDao admDao) {
693 	this.admDao = admDao;
694     }
695 
696     /*
697      * (non-Javadoc)
698      * 
699      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#setup()
700      */
701     @Override
702     public void setup() {
703 	super.setup();
704 	acceptedPatterns = ImporterHelper.compileRegex(importerConfig
705 		.getAcceptRegExString());
706     }
707 
708     /*
709      * (non-Javadoc)
710      * 
711      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#tearDown()
712      */
713     @Override
714     protected void tearDown() {
715     String savedMessage =this.statusMessage;
716     this.statusMessage=internationalisationService.getString("import.teardown");
717     try {
718 	super.tearDown();
719 	if (!solRSynchroniser.commit()){
720 	    logger.warn("The commit in tearDown of "+this.getClass().getSimpleName()+" has failed, the uncommitted changes will be commited with the auto commit of solr in few minuts");
721 	}
722 	solRSynchroniser.optimize();
723     } finally{
724     	this.statusMessage=savedMessage;
725     }
726     }
727 
728     /**
729      * @param countryDao
730      *                The countryDao to set
731      */
732     @Required
733     public void setCountryDao(ICountryDao countryDao) {
734 	this.countryDao = countryDao;
735     }
736 
737     /*
738      * (non-Javadoc)
739      * 
740      * @see com.gisgraphy.domain.geoloc.importer.AbstractImporterProcessor#getFiles()
741      */
742     @Override
743     protected File[] getFiles() {
744 	return ImporterHelper.listCountryFilesToImport(importerConfig
745 		.getGeonamesDir());
746     }
747 
748     /**
749      * @param solRSynchroniser
750      *                the solRSynchroniser to set
751      */
752     @Required
753     public void setSolRSynchroniser(ISolRSynchroniser solRSynchroniser) {
754 	this.solRSynchroniser = solRSynchroniser;
755     }
756 
757     /**
758      * @param daos
759      *                the iDaos to set
760      */
761     public void setIDaos(IGisDao<? extends GisFeature>[] daos) {
762 	iDaos = daos;
763     }
764 
765     /*
766      * (non-Javadoc)
767      * 
768      * @see com.gisgraphy.domain.geoloc.importer.IGeonamesProcessor#rollback()
769      */
770     public List<NameValueDTO<Integer>> rollback() {
771 	List<NameValueDTO<Integer>> deletedObjectInfo = new ArrayList<NameValueDTO<Integer>>();
772 	// we first reset subClass
773 	for (IGisDao<? extends GisFeature> gisDao : iDaos) {
774 	    if (gisDao.getPersistenceClass() != GisFeature.class
775 		    && gisDao.getPersistenceClass() != Adm.class
776 		    && gisDao.getPersistenceClass() != Country.class) {
777 		logger.warn("deleting "
778 			+ gisDao.getPersistenceClass().getSimpleName() + "...");
779 		// we don't want to remove adm because some feature can be
780 		// linked again
781 		int deletedgis = gisDao.deleteAll();
782 		logger.warn(deletedgis+" "
783 			+ gisDao.getPersistenceClass().getSimpleName()
784 			+ " have been deleted");
785 		if (deletedgis != 0) {
786 		    deletedObjectInfo.add(new NameValueDTO<Integer>(
787 			    GisFeature.class.getSimpleName(), deletedgis));
788 		}
789 	    }
790 	}
791 	logger.warn("deleting gisFeature...");
792 	// we don't want to remove adm because some feature can be linked again
793 	int deletedgis = gisFeatureDao.deleteAllExceptAdmsAndCountries();
794 	logger.warn(deletedgis + " gisFeature have been deleted");
795 	if (deletedgis != 0) {
796 	    deletedObjectInfo.add(new NameValueDTO<Integer>(GisFeature.class
797 		    .getSimpleName(), deletedgis));
798 	}
799 	resetStatus();
800 	return deletedObjectInfo;
801     }
802 
803 
804 }