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.webapp.action;
24  
25  import java.util.Date;
26  import java.util.List;
27  
28  import javax.servlet.http.HttpServletRequest;
29  
30  import org.apache.struts2.ServletActionContext;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  import org.springframework.beans.factory.annotation.Required;
34  import org.springframework.transaction.PlatformTransactionManager;
35  import org.springframework.transaction.TransactionDefinition;
36  import org.springframework.transaction.TransactionStatus;
37  import org.springframework.transaction.support.DefaultTransactionDefinition;
38  
39  import com.gisgraphy.domain.geoloc.entity.Country;
40  import com.gisgraphy.domain.geoloc.entity.GisFeature;
41  import com.gisgraphy.domain.repository.CountryDao;
42  import com.gisgraphy.domain.repository.IGisFeatureDao;
43  import com.gisgraphy.domain.repository.IIdGenerator;
44  import com.gisgraphy.domain.repository.ISolRSynchroniser;
45  import com.gisgraphy.domain.valueobject.FeatureCode;
46  import com.gisgraphy.domain.valueobject.GISSource;
47  import com.gisgraphy.helper.GeolocHelper;
48  import com.gisgraphy.helper.StringHelper;
49  import com.gisgraphy.service.IInternationalisationService;
50  import com.gisgraphy.street.StreetType;
51  import com.opensymphony.xwork2.ActionContext;
52  import com.opensymphony.xwork2.Preparable;
53  import com.vividsolutions.jts.geom.Point;
54  
55  /**
56   * Edit Feature all Geonames Entity, gisfeature and subclass action
57   * 
58   * @author <a href="mailto:david.masclet@gisgraphy.com">David Masclet</a>
59   */
60  public class EditFeatureAction extends BaseAction implements Preparable {
61  
62  	private static final long serialVersionUID = 4785676484073350068L;
63  
64  	private static Logger logger = LoggerFactory
65  			.getLogger(EditFeatureAction.class);
66  
67  	private IGisFeatureDao gisFeatureDao;
68  
69  	private GisFeature gisfeature;
70  
71  	private IInternationalisationService internationalisationService;
72  
73  	private CountryDao countryDao;
74  	
75  	private IIdGenerator IdGenerator;
76  	
77  	private ISolRSynchroniser solRSynchroniser;
78  
79  	private PlatformTransactionManager transactionManager;
80  
81  	private TransactionStatus txStatus = null;
82  
83  	private DefaultTransactionDefinition txDefinition;
84  
85  
86  	/*
87  	 * Those specific fields needs to be process separately because of decimal
88  	 * separator or enum type
89  	 */
90  	private String latitude;
91  	private String longitude;
92  	private Float latitudeAsFloat = null;
93  	private Float longitudeAsFloat = null;
94  	private Long id;
95  	
96  	private String errorMessage;
97  	private String stackTrace;
98  	private String classcode;
99  
100 
101 	/**
102 	 * @return the available countries
103 	 */
104 	public List<Country> getCountries() {
105 		return countryDao.getAllSortedByName();
106 	}
107 
108 	public StreetType[] getStreetTypes() {
109 		return StreetType.values();
110 	}
111 
112 	public void prepare() {
113 		// we have to test httpparameter because prepare is called before the
114 		// setters are called
115 		HttpServletRequest request = (HttpServletRequest) ActionContext
116 				.getContext().get(ServletActionContext.HTTP_REQUEST);
117 		String parameter = request.getParameter("featureid");
118 		if (parameter != null && !parameter.equals("")) {
119 			Long idAsLong=null;
120 			try {
121 			    idAsLong = Long.parseLong(parameter);
122 			} catch (NumberFormatException e) {
123 			    errorMessage="featureid should be numeric";
124 				logger.error(errorMessage);
125 			}
126 			id = idAsLong;
127 		}
128 		if (gisfeature != null && gisfeature.getId() != null) {
129 			gisfeature = gisFeatureDao.get(gisfeature.getId());
130 		} else if (id != null) {
131 			gisfeature = gisFeatureDao.getByFeatureId(getId());
132 		}
133 	}
134 
135 	public String input() {
136 		return INPUT;
137 	}
138 
139 	public String save() {
140 		return doSave();
141 	}
142 	
143 	public FeatureCode[] getPlacetypes(){
144 		return FeatureCode.values();
145 	}
146 
147 	public String doSave() {
148 		if (gisfeature != null) {
149 			checkMissingRequiredfields();
150 			//we sync the idgenerator in case an import is in progress
151 			//or several person add street simultaneously
152 			IdGenerator.sync();
153 			if (gisfeature.getFeatureId()==null){
154 			    gisfeature.setFeatureId(generateFeatureId());
155 			}
156 			gisfeature.setLocation(processPoint());
157 			processFeatureClassCode(gisfeature);
158 			gisfeature.setSource(GISSource.PERSONAL);
159 			gisfeature.setModificationDate(new Date());
160 			if (getFieldErrors().keySet().size() > 0) {
161 				return INPUT;
162 			} else {
163 				startTransaction();
164 				try {
165 				    	if (gisfeature.getId()== null){
166 				    	gisfeature = getObjectFromFeatureClassCode(gisfeature);
167 				    	}
168 					gisFeatureDao.save(gisfeature);
169 				} catch (Exception e) {
170 					rollbackTransaction();
171 					errorMessage="could not save feature " + e.getMessage();
172 					stackTrace= StringHelper.getStackTraceAsString(e);
173 					logger.error(errorMessage, e);
174 					return ERROR;
175 				}
176 				commitTransaction();
177 				return SUCCESS;
178 			}
179 		} else {
180 			errorMessage="There is no feature to save";
181 			logger.error(errorMessage);
182 			return ERROR;
183 		}
184 	}
185 
186 	protected void processFeatureClassCode(GisFeature feature) {
187 		if (classcode!=null && !"".equals(classcode.trim())){
188 			try {
189 				String[] splited = classcode.split("_");
190 				if (splited.length!=2){
191 					logger.warn("featurecode should be separated by '_'");
192 					return;
193 				}
194 				feature.setFeatureClass(splited[0]);
195 				feature.setFeatureCode(splited[1]);
196 			} catch (Exception e) {
197 				logger.warn("feature code "+classcode+" is not valid");
198 				return;
199 			}
200 		} else {
201 			feature.setFeatureClass(null);
202 			feature.setFeatureCode(null);
203 		}
204 		
205 	}
206 	
207 	protected GisFeature getObjectFromFeatureClassCode(GisFeature feature) {
208 		if (classcode!=null && !"".equals(classcode.trim())){
209 			try {
210 				FeatureCode featureCode = FeatureCode.valueOf(classcode);
211 				GisFeature placeType = featureCode.getObject();
212 				if (placeType==null){
213 				    logger.error("can not detemine placetype, the object retuned from classcode is null");
214 				    return gisfeature;
215 				}
216 				 placeType.populate(feature);
217 				 logger.info("class code correspond to placetype "+ placeType.getClass().getSimpleName());
218 				 return placeType;
219 				
220 				
221 			} catch (Exception e) {
222 				logger.warn("feature code "+classcode+" is not valid to determine the placetype");
223 				return gisfeature;
224 			}
225 		} else {
226 			return feature;
227 		}
228 		
229 	}
230 
231 	private void checkMissingRequiredfields() {
232 		if (getLatitude()==null){
233 			addFieldError("latitude",internationalisationService.getString("errors.required", new String[]{"latitude"}) );
234 		}
235 		if (getLongitude()==null){
236 			addFieldError("longitude",internationalisationService.getString("errors.required", new String[]{"longitude"}) );
237 		}
238 		if (gisfeature!=null && (gisfeature.getName()==null || gisfeature.getName().trim().equals(""))){
239 			addFieldError("name",internationalisationService.getString("errors.required", new String[]{"name"}) );
240 		}
241 		if (gisfeature!=null && (gisfeature.getCountryCode()==null || gisfeature.getCountryCode().trim().equals(""))){
242 			addFieldError("country",internationalisationService.getString("errors.required", new String[]{"country"}) );
243 		}
244 	}
245 
246 	private void commitTransaction() {
247 		transactionManager.commit(txStatus);
248 		solRSynchroniser.commit();
249 	}
250 
251 	private void rollbackTransaction() {
252 		transactionManager.rollback(txStatus);
253 	}
254 
255 	private void startTransaction() {
256 		txDefinition = new DefaultTransactionDefinition();
257 		txDefinition
258 				.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
259 		txDefinition.setReadOnly(false);
260 
261 		txStatus = transactionManager.getTransaction(txDefinition);
262 	}
263 
264 	
265 	protected Point processPoint() {
266 		try {
267 			if (latitude != null) {
268 				try {
269 					latitudeAsFloat = GeolocHelper
270 							.parseInternationalDouble(latitude);
271 					if (latitudeAsFloat < -90 || latitudeAsFloat > 90) {
272 						addFieldError("latitude",
273 								internationalisationService
274 										.getString("error.latitude.outOfRange"));
275 					}
276 				} catch (Exception e) {
277 					logger.warn("latitude : " + latitude + "is not a number");
278 					addFieldError("latitude",
279 							internationalisationService.getString(
280 									"error.notANumber",
281 									new String[] { "latitude" }));
282 				}
283 
284 			}
285 			if (longitude != null) {
286 				try {
287 					longitudeAsFloat = GeolocHelper
288 							.parseInternationalDouble(longitude);
289 					if (longitudeAsFloat < -180 || longitudeAsFloat > 180) {
290 						addFieldError(
291 								"longitude",
292 								internationalisationService
293 										.getString("error.longitude.outOfRange"));
294 					}
295 				} catch (Exception e) {
296 					logger.warn("longitude : " + longitude + "is not a number");
297 					addFieldError("longitude",
298 							internationalisationService.getString(
299 									"error.notANumber",
300 									new String[] { "longitude" }));
301 				}
302 			}
303 
304 			Point point = null;
305 			if (latitudeAsFloat != null && longitudeAsFloat != null) {
306 				point = GeolocHelper.createPoint(longitudeAsFloat,
307 						latitudeAsFloat);
308 				return point;
309 			} else {
310 				return null;
311 			}
312 		} catch (Exception e) {
313 			logger.warn("can not determine point for lat/long : " + latitude
314 					+ "/" + longitude);
315 			addFieldError("latitude",
316 					internationalisationService
317 							.getString("error.not.gps.point"));
318 			return null;
319 		}
320 
321 	}
322 
323 	protected long generateFeatureId() {
324 		return IdGenerator.getNextFeatureId();
325 	}
326 
327 	public Long getId() {
328 		return id;
329 	}
330 
331 	public void setId(Long id) {
332 		this.id = id;
333 	}
334 
335 
336 	public String doDelete() {
337 		if (gisfeature!=null){
338 		startTransaction();
339 		try{
340 		gisFeatureDao.remove(gisfeature);
341 		} catch (Exception e){
342 			logger.error("Can not delete the street : "+e.getMessage(),e);
343 			stackTrace= StringHelper.getStackTraceAsString(e);
344 			rollbackTransaction();
345 			return ERROR;
346 		}
347 		commitTransaction();
348 		return SUCCESS;
349 		} else {
350 			errorMessage="there is no entity to delete";
351 			return ERROR;
352 		}
353 	}
354 
355 
356 	public String getLatitude() {
357 		return latitude;
358 	}
359 
360 	public void setLatitude(String latitude) {
361 		this.latitude = latitude;
362 	}
363 
364 	public String getLongitude() {
365 		return longitude;
366 	}
367 
368 	public void setLongitude(String longitude) {
369 		this.longitude = longitude;
370 	}
371 
372 	/**
373 	 * @return the errorMessage
374 	 */
375 	public String getErrorMessage() {
376 		return errorMessage;
377 	}
378 
379 	/**
380 	 * @param errorMessage the errorMessage to set
381 	 */
382 	public void setErrorMessage(String errorMessage) {
383 		this.errorMessage = errorMessage;
384 	}
385 
386 	/**
387 	 * @return the stackTrace
388 	 */
389 	public String getStackTrace() {
390 		return stackTrace;
391 	}
392 
393 	/**
394 	 * @param stackTrace the stackTrace to set
395 	 */
396 	public void setStackTrace(String stackTrace) {
397 		this.stackTrace = stackTrace;
398 	}
399 
400 	/**
401 	 * @return the gisfeature
402 	 */
403 	public GisFeature getGisfeature() {
404 		return gisfeature;
405 	}
406 
407 	public void setGisfeature(GisFeature gisfeature) {
408 		this.gisfeature = gisfeature;
409 	}
410 
411 
412 	@Required
413 	public void setCountryDao(CountryDao countryDao) {
414 		this.countryDao = countryDao;
415 	}
416 
417 	@Required
418 	public void setGisFeatureDao(IGisFeatureDao gisFeatureDao) {
419 		this.gisFeatureDao = gisFeatureDao;
420 	}
421 
422 	@Required
423 	public void setTransactionManager(
424 			PlatformTransactionManager transactionManager) {
425 		this.transactionManager = transactionManager;
426 	}
427 
428 	@Required
429 	public void setInternationalisationService(
430 			IInternationalisationService internationalisationService) {
431 		this.internationalisationService = internationalisationService;
432 	}
433 
434 	
435 	@Required
436 	public void setIdGenerator(IIdGenerator idGenerator) {
437 		IdGenerator = idGenerator;
438 	}
439 	
440 	@Required
441 	public void setSolRSynchroniser(ISolRSynchroniser solRSynchroniser) {
442 	    this.solRSynchroniser = solRSynchroniser;
443 	}
444 
445 	/**
446 	 * @return the classcode
447 	 */
448 	public String getClasscode() {
449 		return classcode;
450 	}
451 
452 	/**
453 	 * @param classcode the classcode to set
454 	 */
455 	public void setClasscode(String classcode) {
456 		this.classcode = classcode;
457 	}
458 
459 }