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.domain.repository;
24  
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Locale;
30  import java.util.Map;
31  import java.util.Set;
32  import java.util.SortedSet;
33  
34  import org.apache.solr.common.SolrInputDocument;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  import org.springframework.util.Assert;
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.Country;
43  import com.gisgraphy.domain.geoloc.entity.GisFeature;
44  import com.gisgraphy.domain.geoloc.entity.HouseNumber;
45  import com.gisgraphy.domain.geoloc.entity.Language;
46  import com.gisgraphy.domain.geoloc.entity.Street;
47  import com.gisgraphy.domain.geoloc.entity.ZipCode;
48  import com.gisgraphy.domain.geoloc.entity.event.GisFeatureDeleteAllEvent;
49  import com.gisgraphy.domain.geoloc.entity.event.GisFeatureDeletedEvent;
50  import com.gisgraphy.domain.geoloc.entity.event.GisFeatureStoredEvent;
51  import com.gisgraphy.domain.geoloc.entity.event.IEvent;
52  import com.gisgraphy.domain.geoloc.entity.event.PlaceTypeDeleteAllEvent;
53  import com.gisgraphy.fulltext.FullTextFields;
54  import com.gisgraphy.fulltext.IsolrClient;
55  import com.gisgraphy.geoloc.GisgraphyCommunicationException;
56  import com.gisgraphy.helper.ClassNameHelper;
57  import com.gisgraphy.helper.EncodingHelper;
58  import com.gisgraphy.helper.RetryOnErrorTemplate;
59  import com.gisgraphy.street.HouseNumberComparator;
60  import com.gisgraphy.street.HouseNumberSerializer;
61  
62  /**
63   * Interface of data access object for {@link Language}
64   * 
65   * @see ISolRSynchroniser
66   * @author <a href="mailto:david.masclet@gisgraphy.com">David Masclet</a>
67   */
68  public class SolRSynchroniser implements ISolRSynchroniser {
69  	
70  	HouseNumberSerializer houseNumberListSerializer = new HouseNumberSerializer();
71  	HouseNumberComparator houseNumberComparator = new HouseNumberComparator();
72      
73      private static int numberOfRetryOnFailure = 3;
74  
75      /**
76       * Needed by cglib
77       */
78      @SuppressWarnings("unused")
79      private SolRSynchroniser() {
80  
81      }
82  
83      protected static final Logger logger = LoggerFactory
84  	    .getLogger(SolRSynchroniser.class);
85  
86      private IsolrClient solClient;
87  
88      public SolRSynchroniser(IsolrClient solrClient) {
89  	Assert
90  		.notNull(solrClient,
91  			"can not instanciate solRsynchroniser because the solrClient is null");
92  	this.solClient = solrClient;
93      }
94  
95      /**
96       * @param gisFeatureEvent
97       */
98      private void handleEvent(final GisFeatureDeletedEvent gisFeatureEvent) {
99  	try {
100 	    RetryOnErrorTemplate<Object> retryOnError = new RetryOnErrorTemplate<Object>() {
101 		    @Override
102 		    public String tryThat() throws Exception {
103 			solClient.getServer().deleteById(
104 				    gisFeatureEvent.getGisFeature().getFeatureId().toString());
105 			    solClient.getServer().commit(true, true);
106 			    return null;
107 		    }
108 		};
109 		retryOnError.setLoggingSentence("Synchronise SolR : deletion of feature with id="+gisFeatureEvent.getGisFeature().getFeatureId());
110 		retryOnError.times(numberOfRetryOnFailure);
111 	    
112 	    
113 	} catch (Exception e) {
114 	    throw new GisgraphyCommunicationException("Can not synchronise SolR : can not delete feature with id="+gisFeatureEvent.getGisFeature().getFeatureId(),e.getCause());
115 	} 
116     }
117 
118     /*
119      * (non-Javadoc)
120      * 
121      * @see com.gisgraphy.domain.repository.ISolRSynchroniser#deleteAll()
122      */
123     public void deleteAll() {
124 	try {
125 	    RetryOnErrorTemplate<Object> retryOnError = new RetryOnErrorTemplate<Object>() {
126 		    @Override
127 		    public String tryThat() throws Exception {
128 			 logger.info("The entire index will be reset");
129 			    solClient.getServer().deleteByQuery("*:*");
130 			    solClient.getServer().commit(true,true);
131 			    solClient.getServer().optimize(true,true);
132 			    return null;
133 		    }
134 		};
135 		retryOnError.setLoggingSentence("Synchronise SolR : deletion of all features");
136 		retryOnError.times(numberOfRetryOnFailure);
137 	    
138 	    
139 	} catch (Exception e) {
140 	    throw new GisgraphyCommunicationException("Can not synchronise SolR : can not delete all features",e.getCause());
141 	}
142     }
143 
144     /*
145      * (non-Javadoc)
146      * 
147      * @see com.gisgraphy.domain.repository.ISolRSynchroniser#deleteAll()
148      */
149     public void handleEvent(PlaceTypeDeleteAllEvent placeTypeDeleteAllEvent) {
150 	deleteAllByPlaceType(placeTypeDeleteAllEvent.getPlaceType());
151     }
152 
153     public void deleteAllByPlaceType(final Class<? extends GisFeature> placetype) {
154 	try {
155 	    RetryOnErrorTemplate<Object> retryOnError = new RetryOnErrorTemplate<Object>() {
156 		    @Override
157 		    public String tryThat() throws Exception {
158 			  logger.info("GisFeature of type"
159 				    + placetype.getClass().getSimpleName() + " will be reset");
160 			    solClient.getServer().deleteByQuery(
161 				    FullTextFields.PLACETYPE.getValue() + ":"
162 					    + placetype.getSimpleName());
163 			    solClient.getServer().commit(true,true);
164 			    solClient.getServer().optimize(true,true);
165 			    return null;
166 		    }
167 		};
168 		retryOnError.setLoggingSentence("Synchronise SolR : deletion of features of type="+placetype.getClass().getSimpleName());
169 		retryOnError.times(numberOfRetryOnFailure);
170 	    
171 	    
172 	} catch (Exception e) {
173 	    throw new GisgraphyCommunicationException("Can not synchronise SolR : can not delete all "+placetype.getClass().getSimpleName(),e.getCause());
174 	}
175     }
176 
177     private void handleEvent(final GisFeatureDeleteAllEvent gisFeatureDeleteAllEvent) {
178 	try {
179 	    RetryOnErrorTemplate<Object> retryOnError = new RetryOnErrorTemplate<Object>() {
180 		    @Override
181 		    public String tryThat() throws Exception {
182 			 for (GisFeature gisFeature : gisFeatureDeleteAllEvent
183 				    .getGisFeatures()) {
184 				solClient.getServer().deleteById(
185 					gisFeature.getFeatureId().toString());
186 			    }
187 			    solClient.getServer().commit(true, true);
188 			    return null;
189 		    }
190 		};
191 		retryOnError.setLoggingSentence("Synchronise SolR : deletion of specific features");
192 		retryOnError.times(numberOfRetryOnFailure);
193 	    
194 	    
195 	} catch (Exception e) {
196 	    throw new GisgraphyCommunicationException("Can not synchronise SolR : Can not delete the specified features ",e.getCause());
197 	}
198     }
199 
200     /*
201      * (non-Javadoc)
202      * 
203      * @see com.gisgraphy.domain.repository.ISolRSynchroniser#handleEvent(com.gisgraphy.domain.geoloc.entity.event.IEvent)
204      */
205     public void handleEvent(IEvent event) {
206 	logger.debug("An event has been received ");
207 	if (event instanceof GisFeatureStoredEvent) {
208 	    handleEvent((GisFeatureStoredEvent) event);
209 	} else if (event instanceof GisFeatureDeletedEvent) {
210 	    handleEvent((GisFeatureDeletedEvent) event);
211 	} else if (event instanceof GisFeatureDeleteAllEvent) {
212 	    handleEvent((GisFeatureDeleteAllEvent) event);
213 	} else if (event instanceof PlaceTypeDeleteAllEvent) {
214 	    handleEvent((PlaceTypeDeleteAllEvent) event);
215 	} else {
216 	    logger.debug("unknow event " + event.getClass().getSimpleName());
217 	}
218     }
219 
220     /*
221      * (non-Javadoc)
222      * 
223      * @see com.gisgraphy.domain.repository.ISolRSynchroniser#commit()
224      */
225     public boolean commit() {
226 	try {
227 	    RetryOnErrorTemplate<Boolean> retryOnError = new RetryOnErrorTemplate<Boolean>() {
228 		    @Override
229 		    public Boolean tryThat() throws Exception {
230 			solClient.getServer().commit(true, true);
231 			return true;
232 		    }
233 		};
234 		retryOnError.setLoggingSentence("Synchronise SolR : commit");
235 		return retryOnError.times(numberOfRetryOnFailure);
236 	    
237 	    
238 	} catch (Exception e) {
239 	    logger.error("Can not synchronise SolR : can not commit ",e.getCause());
240 	    return false;
241 	}
242     }
243 
244     /*
245      * (non-Javadoc)
246      * 
247      * @see com.gisgraphy.domain.repository.ISolRSynchroniser#optimize()
248      */
249     public void optimize() {
250 	try {
251 	    RetryOnErrorTemplate<Boolean> retryOnError = new RetryOnErrorTemplate<Boolean>() {
252 		    @Override
253 		    public Boolean tryThat() throws Exception {
254 			solClient.getServer().optimize(true,true);
255 			return true;
256 		    }
257 		};
258 		retryOnError.setLoggingSentence("Synchronise SolR : optimize");
259 		retryOnError.times(numberOfRetryOnFailure);
260 	    
261 	    
262 	} catch (Exception e) {
263 	  throw new GisgraphyCommunicationException("Can not synchronise SolR : can not optimize : "+e.getMessage(),e.getCause());
264 	}
265     }
266 
267     private void handleEvent(final GisFeatureStoredEvent gisfeatureCreatedEventEvent) {
268 	try {
269 	    RetryOnErrorTemplate<Boolean> retryOnError = new RetryOnErrorTemplate<Boolean>() {
270 		    @Override
271 		    public Boolean tryThat() throws Exception {
272 			SolrInputDocument ex = new SolrInputDocument();
273 			GisFeature gisFeature = gisfeatureCreatedEventEvent.getGisFeature();
274 
275 			if (gisFeature == null) {
276 			    logger.info("Can not synchronize a null gisFeature");
277 			    return false;
278 			}
279 			if (gisFeature.getFeatureId() == null || gisFeature.getFeatureId() <= 0) {
280 			    logger
281 				    .info("Can not synchronize GisFeature with wrong featureId : "
282 					    + gisFeature.getFeatureId());
283 			    return false;
284 			}
285 
286 			if (gisFeature.getLatitude() == 0 && gisFeature.getLongitude() == 0) {
287 			    logger.info("Can not synchronize GisFeature "
288 				    + gisFeature.getFeatureId() + " with wrong Location "
289 				    + gisFeature.getName() + ": [" + gisFeature.getLongitude()
290 				    + "," + gisFeature.getLatitude() + "]");
291 			    return false;
292 			}
293 			
294 			
295 			if (!gisFeature.isFullTextSearchable()) {
296 			    logger.debug(gisFeature.getClass().getSimpleName()
297 				    + " is not FullTextSearchable");
298 			    return false;
299 			}
300 
301 			ex.setField(FullTextFields.FEATUREID.getValue(), gisFeature
302 				.getFeatureId());
303 			if (gisFeature.getName()!=null && !gisFeature.getName().trim().equals("")){
304 			ex.setField(FullTextFields.NAME.getValue(), EncodingHelper
305 				.toUTF8(gisFeature.getName()));
306 			}
307 			ex.setField(FullTextFields.LAT.getValue(), gisFeature.getLatitude());
308 			ex.setField(FullTextFields.LONG.getValue(), gisFeature.getLongitude());
309 			String latAsString = String.format(Locale.US, "%s", gisFeature.getLatitude().doubleValue());
310 			String lngAsString = String.format(Locale.US, "%s", gisFeature.getLongitude().doubleValue());
311 			ex.setField(FullTextFields.LOCATION.getValue(), latAsString+","+lngAsString);
312 			ex.setField(FullTextFields.OPENSTREETMAP_ID.getValue(), gisFeature.getOpenstreetmapId());
313 			
314 			String placetype = ClassNameHelper.stripEnhancerClass(gisFeature
315 					.getClass().getSimpleName());
316 				ex.setField(FullTextFields.PLACETYPE.getValue(), placetype);
317 			String countryCode = gisFeature.getCountryCode();
318 			if (countryCode != null) {
319 				    ex.setField(FullTextFields.COUNTRYCODE.getValue(), gisFeature.getCountryCode().toUpperCase());
320 				    //Since V4.0, we don't preprocess some field for memory storage 
321 				   /* ex.setField(FullTextFields.COUNTRY_FLAG_URL.getValue(), URLUtils
322 							.createCountryFlagUrl(gisFeature.getCountryCode()));*/
323 				}
324 			if (gisFeature.getIsIn()!=null && !gisFeature.getIsIn().trim().equals("")){
325 	    	    ex.setField(FullTextFields.IS_IN.getValue(), gisFeature.getIsIn());
326 	    	}
327 	    	if (gisFeature.getIsInPlace()!=null && !gisFeature.getIsInPlace().trim().equals("")){
328 	    	    ex.setField(FullTextFields.IS_IN_PLACE.getValue(), gisFeature.getIsInPlace());
329 	    	}
330 	    	if (gisFeature.getIsInAdm()!=null && !gisFeature.getIsInAdm().trim().equals("")){
331 	    	    ex.setField(FullTextFields.IS_IN_ADM.getValue(), gisFeature.getIsInAdm());
332 	    	}
333 	    	if (gisFeature.getIsInZip()!=null && gisFeature.getIsInZip().size()>0){
334 	    	    ex.setField(FullTextFields.IS_IN_ZIP.getValue(), gisFeature.getIsInZip() );
335 	    	}
336 			if (gisFeature instanceof City){
337 				ex.setField(FullTextFields.MUNICIPALITY.getValue(), ((City) gisFeature).isMunicipality());
338 			}
339 			if (gisFeature.getIsInCityAlternateNames()!=null && gisFeature.getIsInCityAlternateNames().size()>0){
340 				ex.setField(FullTextFields.IS_IN_CITIES.getValue(), gisFeature.getIsInCityAlternateNames() );
341 			}
342 		    if (gisFeature instanceof Street) {
343 		    	ex.setField(FullTextFields.LENGTH.getValue(), ((Street) gisFeature).getLength());
344 		    	ex.setField(FullTextFields.ONE_WAY.getValue(), ((Street) gisFeature).isOneWay());
345 		    	ex.setField(FullTextFields.STREET_TYPE.getValue(), ((Street) gisFeature).getStreetType());
346 		    	ex.setField(FullTextFields.CITY_POPULATION.getValue(), ((Street) gisFeature).getPopulation());
347 		    	
348 		    	/*if (((Street) gisFeature).getFullyQualifiedAddress()!=null && !((Street) gisFeature).getFullyQualifiedAddress().trim().equals("")){
349 		    	    ex.setField(FullTextFields.FULLY_QUALIFIED_ADDRESS.getValue(), ((Street) gisFeature).getFullyQualifiedAddress());
350 		    	}*/
351 		    	SortedSet<HouseNumber> houseNumbersFromEntity = ((Street) gisFeature).getHouseNumbers();
352 		    	if (houseNumbersFromEntity!=null && houseNumbersFromEntity.size()!=0){
353 			    	//SortedSet<HouseNumber> houseNumbers = new TreeSet<HouseNumber>(houseNumberComparator);
354 					//houseNumbers.addAll(houseNumbersFromEntity);
355 						 List<String> houseNumbersToAdd= new ArrayList<String>();
356 						// Collections.sort(houseNumbers,houseNumberComparator);
357 			    		for (HouseNumber houseNumber:houseNumbersFromEntity){
358 			    			houseNumbersToAdd.add(houseNumberListSerializer.serialize(houseNumber));
359 			    		}
360 			    		ex.setField(FullTextFields.HOUSE_NUMBERS.getValue(),houseNumbersToAdd );
361 		    	}
362 				populateAlternateNamesForStreet(gisFeature.getAlternateNames(),ex);
363 		    } else {
364 			
365 			ex.setField(FullTextFields.FEATURECLASS.getValue(), gisFeature
366 				.getFeatureClass());
367 			ex.setField(FullTextFields.FEATURECODE.getValue(), gisFeature
368 				.getFeatureCode());
369 			if (gisFeature.getAsciiName()!=null && !gisFeature.getAsciiName().trim().equals("")){
370 			ex.setField(FullTextFields.NAMEASCII.getValue(), gisFeature
371 				.getAsciiName());
372 			}
373 			
374 			ex.setField(FullTextFields.ELEVATION.getValue(), gisFeature
375 				.getElevation());
376 			ex.setField(FullTextFields.AMENITY.getValue(), gisFeature
377 					.getAmenity());
378 			ex.setField(FullTextFields.GTOPO30.getValue(), gisFeature.getGtopo30());
379 			ex.setField(FullTextFields.TIMEZONE.getValue(), gisFeature
380 				.getTimezone());
381 			
382 			ex.setField(FullTextFields.POPULATION.getValue(), gisFeature
383 				.getPopulation());
384 			//Since V 4.0 all processed field are not processed dur reduce datastorage)
385 			/*ex.setField(FullTextFields.FULLY_QUALIFIED_NAME.getValue(),
386 				EncodingHelper.toUTF8(gisFeature.getFullyQualifiedName(false)));
387 			ex.setField(FullTextFields.GOOGLE_MAP_URL.getValue(), URLUtils
388 				.createGoogleMapUrl(gisFeature.getLocation(), gisFeature
389 					.getName()));
390 			ex.setField(FullTextFields.YAHOO_MAP_URL.getValue(), URLUtils
391 				.createYahooMapUrl(gisFeature.getLocation()));
392 			ex.setField(FullTextFields.OPENSTREETMAP_MAP_URL.getValue(), URLUtils
393 					.createOpenstreetmapMapUrl(gisFeature.getLocation()));*/
394 			
395 			// setAdmCode from adm not from the gisfeature one because of
396 			// syncAdmCodesWithLinkedAdmOnes if it is false , the value may not be
397 			// the same
398 			Adm adm = null;
399 
400 			if (gisFeature instanceof Adm) {
401 			    adm = (Adm) gisFeature;
402 			    ex.setField(FullTextFields.LEVEL.getValue(), adm.getLevel());
403 			    
404 			} else {
405 			    adm = gisFeature.getAdm();
406 			}
407 			// we set admCode once for all
408 			if (adm != null) {
409 			    ex.setField(FullTextFields.ADM1CODE.getValue(), adm.getAdm1Code());
410 			    ex.setField(FullTextFields.ADM2CODE.getValue(), adm.getAdm2Code());
411 			    ex.setField(FullTextFields.ADM3CODE.getValue(), adm.getAdm3Code());
412 			    ex.setField(FullTextFields.ADM4CODE.getValue(), adm.getAdm4Code());
413 			}
414 			while (adm != null) {
415 			    int level = adm.getLevel();
416 			    String admLevelName = FullTextFields
417 				    .valueOf("ADM" + level + "NAME").getValue();
418 			    ex.setField(admLevelName, EncodingHelper.toUTF8(adm.getName()));
419 			    if (level == 1 || level == 2) {
420 				populateAlternateNames(admLevelName, adm.getAlternateNames(),
421 					ex);
422 			    }
423 			    adm = adm.getParent();
424 			}
425 				Set<ZipCode> zipCodes =gisFeature.getZipCodes();
426 				if (zipCodes != null) {
427 					List<String> zipCodesToAdd = new ArrayList<String>();
428 					for (ZipCode zipCode:zipCodes){
429 						zipCodesToAdd.add(zipCode.getCode().trim());
430 					}
431 				    ex.setField(FullTextFields.ZIPCODE.getValue(),zipCodesToAdd);
432 				}
433 			   
434 
435 			// No prefix for cities
436 
437 			Collection<AlternateName> alternatenames = gisFeature.getAlternateNames();
438 			populateAlternateNames(FullTextFields.NAME.getValue(), alternatenames,
439 				ex);
440 
441 			// we don't want this fields
442 			// populateAlternateNames("adm3_", adm2.getAlternateNames(), ex);
443 			// populateAlternateNames("adm4_", adm1.getAlternateNames(), ex);
444 			if (gisFeature instanceof Country) {
445 			    Country country = (Country) gisFeature;
446 			    ex.setField(FullTextFields.CONTINENT.getValue(), country
447 				    .getContinent());
448 			    ex.setField(FullTextFields.CURRENCY_CODE.getValue(), country
449 				    .getCurrencyCode());
450 			    ex.setField(FullTextFields.CURRENCY_NAME.getValue(), country
451 				    .getCurrencyName());
452 			    ex.setField(FullTextFields.FIPS_CODE.getValue(), country
453 				    .getFipsCode());
454 			    ex.setField(FullTextFields.ISOALPHA2_COUNTRY_CODE.getValue(),
455 				    country.getIso3166Alpha2Code());
456 			    ex.setField(FullTextFields.ISOALPHA3_COUNTRY_CODE.getValue(),
457 				    country.getIso3166Alpha3Code());
458 			    ex.setField(FullTextFields.COUNTRYCODE.getValue(), country.getCountryCode()
459 					.toUpperCase());
460 			    ex.setField(FullTextFields.POSTAL_CODE_MASK.getValue(), country
461 				    .getPostalCodeMask());
462 			    ex.setField(FullTextFields.POSTAL_CODE_REGEX.getValue(), country
463 				    .getPostalCodeRegex());
464 			    ex.setField(FullTextFields.PHONE_PREFIX.getValue(), country
465 				    .getPhonePrefix());
466 			    List<Language> spokenLanguages = country.getSpokenLanguages();
467 			    if (spokenLanguages.size() > 0){
468 				    List<String> languagesToAdd= new ArrayList<String>();
469 					for (Language language : spokenLanguages) {
470 					languagesToAdd.add(language.getIso639LanguageName());
471 				    }
472 					ex.setField(FullTextFields.SPOKEN_LANGUAGES.getValue(),
473 							languagesToAdd);
474 			    }
475 			    ex.setField(FullTextFields.TLD.getValue(), country.getTld());
476 			    ex.setField(FullTextFields.CAPITAL_NAME.getValue(), country
477 				    .getCapitalName());
478 			    ex.setField(FullTextFields.AREA.getValue(), country.getArea());
479 			    populateAlternateNames(FullTextFields.COUNTRYNAME
480 				    .getValue(), country.getAlternateNames(), ex);
481 			    if (country.getName()!=null){
482 			    ex.setField(FullTextFields.COUNTRYNAME.getValue(),
483 				    EncodingHelper.toUTF8(country.getName()));
484 			    }
485 			} else {
486 			    if (countryCode != null) {
487 				Country country = gisFeature.getCountry();
488 				if (country != null) {
489 				    populateAlternateNames(FullTextFields.COUNTRYNAME
490 					    .getValue(), country.getAlternateNames(), ex);
491 				    if (country.getName()!=null){
492 				    ex.setField(FullTextFields.COUNTRYNAME.getValue(),
493 					    EncodingHelper.toUTF8(country.getName()));
494 				    }
495 				} else {
496 				    logger.error("Can not find country with code "
497 					    + gisFeature.getCountryCode() + " for "
498 					    + gisFeature);
499 				}
500 			    }
501 			}
502 			}
503 			solClient.getServer().add(ex);
504 			return true;
505 		    }
506 		};
507 		retryOnError.setLoggingSentence("Synchronise SolR : Add feature with id "+gisfeatureCreatedEventEvent.getGisFeature());
508 		retryOnError.times(numberOfRetryOnFailure);
509 	    
510 	    
511 	} catch (Exception e) {
512 	  throw new GisgraphyCommunicationException("Can not synchronise SolR : can not synchronize  "+gisfeatureCreatedEventEvent.getGisFeature()+":" +e,e.getCause());
513 	}
514     }
515     
516     //Same as gisfeature but ignore language 
517     private void populateAlternateNamesForStreet(Collection<AlternateName> alternateNames, SolrInputDocument ex) {
518     	if (alternateNames == null || alternateNames.size() == 0) {
519     	    return;
520     	}
521     	List<String> alternateNamesStrings = new ArrayList<String>();
522     	for (AlternateName alternateName:alternateNames){
523     		if (alternateName!=null){
524     			alternateNamesStrings.add(alternateName.getName().trim());
525     		}
526     	}
527     	
528     	ex.setField(FullTextFields.NAME.getValue()
529     			+ FullTextFields.ALTERNATE_NAME_SUFFIX.getValue(),
530     			alternateNamesStrings
531     				.toArray(new String[alternateNames
532     					.size()]));
533     	    }
534 
535     
536     
537     private void populateAlternateNames(String fieldPrefix,
538 	    Collection<AlternateName> alternateNames, SolrInputDocument ex) {
539 	if (alternateNames == null || alternateNames.size() == 0) {
540 	    return;
541 	}
542 
543 	Map<String, List<String>> alternateNamesByAlpha3LanguageCode = new HashMap<String, List<String>>();
544 
545 	List<String> alternateNamesWithoutAnAlpha3Code = new ArrayList<String>();
546 	// List<String> alternateNamesAsStrings = new ArrayList<String>();
547 	if (alternateNames != null) {
548 	    for (AlternateName alternateName : alternateNames) {
549 		String alpha3Code = alternateName.getLanguage();
550 		if (alpha3Code != null){
551 		    alpha3Code = alpha3Code.trim();
552 		}
553 		if (alpha3Code == null || "".equals(alpha3Code)) {
554 		    alternateNamesWithoutAnAlpha3Code.add(EncodingHelper
555 			    .toUTF8(alternateName.getName()));
556 		    continue;
557 		}
558 		alpha3Code = alpha3Code.toLowerCase();
559 		List<String> alternateNamesForCurrentLanguage = alternateNamesByAlpha3LanguageCode
560 			.get(alpha3Code);
561 		if (alternateNamesForCurrentLanguage == null) {
562 		    alternateNamesForCurrentLanguage = new ArrayList<String>();
563 		    alternateNamesByAlpha3LanguageCode.put(alpha3Code,
564 			    alternateNamesForCurrentLanguage);
565 		}
566 		alternateNamesForCurrentLanguage.add(EncodingHelper
567 			.toUTF8(alternateName.getName()));
568 	    }
569 	}
570 
571 	// Traverse the keys in the map, generating the fields in solr
572 	Set<String> keys = alternateNamesByAlpha3LanguageCode.keySet();
573 	for (String key : keys) {
574 	    List<String> alternateNamesForCurrentLanguage = alternateNamesByAlpha3LanguageCode
575 		    .get(key);
576 	    ex
577 		    .setField(
578 			    fieldPrefix
579 				    + FullTextFields.ALTERNATE_NAME_DYNA_SUFFIX
580 					    .getValue() + key.toUpperCase(),
581 			    alternateNamesForCurrentLanguage
582 				    .toArray(new String[alternateNamesForCurrentLanguage
583 					    .size()]));
584 	}
585 
586 	// Handle all the names without alpha 3 codes
587 	ex.setField(fieldPrefix
588 		+ FullTextFields.ALTERNATE_NAME_SUFFIX.getValue(),
589 		alternateNamesWithoutAnAlpha3Code
590 			.toArray(new String[alternateNamesWithoutAnAlpha3Code
591 				.size()]));
592     }
593 
594 }