/*******************************************************************************
* Gisgraphy Project
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
* Copyright 2008 Gisgraphy project
* David Masclet <davidmasclet@gisgraphy.com>
*
*
*******************************************************************************/
package com.gisgraphy.webapp.action;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import com.gisgraphy.domain.geoloc.entity.Country;
import com.gisgraphy.domain.geoloc.entity.GisFeature;
import com.gisgraphy.domain.repository.CountryDao;
import com.gisgraphy.domain.repository.IGisFeatureDao;
import com.gisgraphy.domain.repository.IIdGenerator;
import com.gisgraphy.domain.repository.ISolRSynchroniser;
import com.gisgraphy.domain.valueobject.FeatureCode;
import com.gisgraphy.domain.valueobject.GISSource;
import com.gisgraphy.helper.GeolocHelper;
import com.gisgraphy.helper.StringHelper;
import com.gisgraphy.service.IInternationalisationService;
import com.gisgraphy.street.StreetType;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.Preparable;
import com.vividsolutions.jts.geom.Point;
/**
* Edit Feature all Geonames Entity, gisfeature and subclass action
*
* @author <a href="mailto:david.masclet@gisgraphy.com">David Masclet</a>
*/
public class EditFeatureAction extends BaseAction implements Preparable {
private static final long serialVersionUID = 4785676484073350068L;
private static Logger logger = LoggerFactory
.getLogger(EditFeatureAction.class);
private IGisFeatureDao gisFeatureDao;
private GisFeature gisfeature;
private IInternationalisationService internationalisationService;
private CountryDao countryDao;
private IIdGenerator IdGenerator;
private ISolRSynchroniser solRSynchroniser;
private PlatformTransactionManager transactionManager;
private TransactionStatus txStatus = null;
private DefaultTransactionDefinition txDefinition;
/*
* Those specific fields needs to be process separately because of decimal
* separator or enum type
*/
private String latitude;
private String longitude;
private Float latitudeAsFloat = null;
private Float longitudeAsFloat = null;
private Long id;
private String errorMessage;
private String stackTrace;
private String classcode;
/**
* @return the available countries
*/
public List<Country> getCountries() {
return countryDao.getAllSortedByName();
}
public StreetType[] getStreetTypes() {
return StreetType.values();
}
public void prepare() {
// we have to test httpparameter because prepare is called before the
// setters are called
HttpServletRequest request = (HttpServletRequest) ActionContext
.getContext().get(ServletActionContext.HTTP_REQUEST);
String parameter = request.getParameter("featureid");
if (parameter != null && !parameter.equals("")) {
Long idAsLong=null;
try {
idAsLong = Long.parseLong(parameter);
} catch (NumberFormatException e) {
errorMessage="featureid should be numeric";
logger.error(errorMessage);
}
id = idAsLong;
}
if (gisfeature != null && gisfeature.getId() != null) {
gisfeature = gisFeatureDao.get(gisfeature.getId());
} else if (id != null) {
gisfeature = gisFeatureDao.getByFeatureId(getId());
}
}
public String input() {
return INPUT;
}
public String save() {
return doSave();
}
public FeatureCode[] getPlacetypes(){
return FeatureCode.values();
}
public String doSave() {
if (gisfeature != null) {
checkMissingRequiredfields();
//we sync the idgenerator in case an import is in progress
//or several person add street simultaneously
IdGenerator.sync();
if (gisfeature.getFeatureId()==null){
gisfeature.setFeatureId(generateFeatureId());
}
gisfeature.setLocation(processPoint());
processFeatureClassCode(gisfeature);
gisfeature.setSource(GISSource.PERSONAL);
gisfeature.setModificationDate(new Date());
if (getFieldErrors().keySet().size() > 0) {
return INPUT;
} else {
startTransaction();
try {
if (gisfeature.getId()== null){
gisfeature = getObjectFromFeatureClassCode(gisfeature);
}
gisFeatureDao.save(gisfeature);
} catch (Exception e) {
rollbackTransaction();
errorMessage="could not save feature " + e.getMessage();
stackTrace= StringHelper.getStackTraceAsString(e);
logger.error(errorMessage, e);
return ERROR;
}
commitTransaction();
return SUCCESS;
}
} else {
errorMessage="There is no feature to save";
logger.error(errorMessage);
return ERROR;
}
}
protected void processFeatureClassCode(GisFeature feature) {
if (classcode!=null && !"".equals(classcode.trim())){
try {
String[] splited = classcode.split("_");
if (splited.length!=2){
logger.warn("featurecode should be separated by '_'");
return;
}
feature.setFeatureClass(splited[0]);
feature.setFeatureCode(splited[1]);
} catch (Exception e) {
logger.warn("feature code "+classcode+" is not valid");
return;
}
} else {
feature.setFeatureClass(null);
feature.setFeatureCode(null);
}
}
protected GisFeature getObjectFromFeatureClassCode(GisFeature feature) {
if (classcode!=null && !"".equals(classcode.trim())){
try {
FeatureCode featureCode = FeatureCode.valueOf(classcode);
GisFeature placeType = featureCode.getObject();
if (placeType==null){
logger.error("can not detemine placetype, the object retuned from classcode is null");
return gisfeature;
}
placeType.populate(feature);
logger.info("class code correspond to placetype "+ placeType.getClass().getSimpleName());
return placeType;
} catch (Exception e) {
logger.warn("feature code "+classcode+" is not valid to determine the placetype");
return gisfeature;
}
} else {
return feature;
}
}
private void checkMissingRequiredfields() {
if (getLatitude()==null){
addFieldError("latitude",internationalisationService.getString("errors.required", new String[]{"latitude"}) );
}
if (getLongitude()==null){
addFieldError("longitude",internationalisationService.getString("errors.required", new String[]{"longitude"}) );
}
if (gisfeature!=null && (gisfeature.getName()==null || gisfeature.getName().trim().equals(""))){
addFieldError("name",internationalisationService.getString("errors.required", new String[]{"name"}) );
}
if (gisfeature!=null && (gisfeature.getCountryCode()==null || gisfeature.getCountryCode().trim().equals(""))){
addFieldError("country",internationalisationService.getString("errors.required", new String[]{"country"}) );
}
}
private void commitTransaction() {
transactionManager.commit(txStatus);
solRSynchroniser.commit();
}
private void rollbackTransaction() {
transactionManager.rollback(txStatus);
}
private void startTransaction() {
txDefinition = new DefaultTransactionDefinition();
txDefinition
.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txDefinition.setReadOnly(false);
txStatus = transactionManager.getTransaction(txDefinition);
}
protected Point processPoint() {
try {
if (latitude != null) {
try {
latitudeAsFloat = GeolocHelper
.parseInternationalDouble(latitude);
if (latitudeAsFloat < -90 || latitudeAsFloat > 90) {
addFieldError("latitude",
internationalisationService
.getString("error.latitude.outOfRange"));
}
} catch (Exception e) {
logger.warn("latitude : " + latitude + "is not a number");
addFieldError("latitude",
internationalisationService.getString(
"error.notANumber",
new String[] { "latitude" }));
}
}
if (longitude != null) {
try {
longitudeAsFloat = GeolocHelper
.parseInternationalDouble(longitude);
if (longitudeAsFloat < -180 || longitudeAsFloat > 180) {
addFieldError(
"longitude",
internationalisationService
.getString("error.longitude.outOfRange"));
}
} catch (Exception e) {
logger.warn("longitude : " + longitude + "is not a number");
addFieldError("longitude",
internationalisationService.getString(
"error.notANumber",
new String[] { "longitude" }));
}
}
Point point = null;
if (latitudeAsFloat != null && longitudeAsFloat != null) {
point = GeolocHelper.createPoint(longitudeAsFloat,
latitudeAsFloat);
return point;
} else {
return null;
}
} catch (Exception e) {
logger.warn("can not determine point for lat/long : " + latitude
+ "/" + longitude);
addFieldError("latitude",
internationalisationService
.getString("error.not.gps.point"));
return null;
}
}
protected long generateFeatureId() {
return IdGenerator.getNextFeatureId();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String doDelete() {
if (gisfeature!=null){
startTransaction();
try{
gisFeatureDao.remove(gisfeature);
} catch (Exception e){
logger.error("Can not delete the street : "+e.getMessage(),e);
stackTrace= StringHelper.getStackTraceAsString(e);
rollbackTransaction();
return ERROR;
}
commitTransaction();
return SUCCESS;
} else {
errorMessage="there is no entity to delete";
return ERROR;
}
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
/**
* @return the errorMessage
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* @param errorMessage the errorMessage to set
*/
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
/**
* @return the stackTrace
*/
public String getStackTrace() {
return stackTrace;
}
/**
* @param stackTrace the stackTrace to set
*/
public void setStackTrace(String stackTrace) {
this.stackTrace = stackTrace;
}
/**
* @return the gisfeature
*/
public GisFeature getGisfeature() {
return gisfeature;
}
public void setGisfeature(GisFeature gisfeature) {
this.gisfeature = gisfeature;
}
@Required
public void setCountryDao(CountryDao countryDao) {
this.countryDao = countryDao;
}
@Required
public void setGisFeatureDao(IGisFeatureDao gisFeatureDao) {
this.gisFeatureDao = gisFeatureDao;
}
@Required
public void setTransactionManager(
PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Required
public void setInternationalisationService(
IInternationalisationService internationalisationService) {
this.internationalisationService = internationalisationService;
}
@Required
public void setIdGenerator(IIdGenerator idGenerator) {
IdGenerator = idGenerator;
}
@Required
public void setSolRSynchroniser(ISolRSynchroniser solRSynchroniser) {
this.solRSynchroniser = solRSynchroniser;
}
/**
* @return the classcode
*/
public String getClasscode() {
return classcode;
}
/**
* @param classcode the classcode to set
*/
public void setClasscode(String classcode) {
this.classcode = classcode;
}
}