package demo.processors;
import demo.BatchTemplate;
import demo.geocoders.Geocoder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.Message;
import org.springframework.jdbc.core.*;
import org.springframework.util.Assert;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public abstract class AbstractGeocodingProcessor
extends AbstractBatchProcessor {
private Geocoder googleGeocoder;
private JdbcTemplate jdbcTemplate;
public AbstractGeocodingProcessor(BatchTemplate batchTemplate, JdbcTemplate jdbcTemplate, Geocoder googleGeocoder) {
super(batchTemplate);
this.googleGeocoder = googleGeocoder;
this.jdbcTemplate = jdbcTemplate;
}
public void persistGelocationResult(ResultSet resultSet, AbstractGeocodingProcessor.Address address, Geocoder.LatLong latLong) throws SQLException {
resultSet.updateDouble("latitude", latLong.getLatitude());
resultSet.updateDouble("longitude", latLong.getLongitude());
resultSet.updateRow();
}
protected Geocoder getGeolocationService() {
return googleGeocoder;
}
protected JdbcTemplate getJdbcTemplate() {
return this.jdbcTemplate;
}
@Override
public void doProcessMessage(String batchId, Message msg) {
final RowMapper<Address> addressRowMapper = addressRowMapper();
PreparedStatementCreatorFactory preparedStatementCreatorFactory = new PreparedStatementCreatorFactory(selectSql());
preparedStatementCreatorFactory.setUpdatableResults(true);
preparedStatementCreatorFactory.addParameter(new SqlParameter("batchId", Types.VARCHAR));
PreparedStatementCreator preparedStatementCreator = preparedStatementCreatorFactory.newPreparedStatementCreator(new Object[]{batchId});
RowCallbackHandler rowCallbackHandler = new RowCallbackHandler() {
int offset = 0;
@Override
public void processRow(ResultSet resultSet) throws SQLException {
Address address = addressRowMapper.mapRow(resultSet, offset);
if (address.getLatitude() == null || address.getLongitude() == null) {
Geocoder.LatLong latLong = geocode(address);
if (null != latLong) {
persistGelocationResult(resultSet, address, latLong);
}
}
offset += 1;
}
};
getJdbcTemplate().query(preparedStatementCreator, rowCallbackHandler);
}
public abstract String selectSql();
public Geocoder.LatLong geocode(Address address) {
Assert.notNull(address, "the provided address can't be null");
String addy = address.getAddress(),
city = address.getCity(),
state = address.getState(),
zipcode = address.getPostalCode(),
country = address.getCountry();
// do we have enough for a full geolocation?
boolean hasAllFields =
!StringUtils.isEmpty(city) && !StringUtils.isEmpty(state) &&
!StringUtils.isEmpty(addy) && !StringUtils.isEmpty(zipcode) &&
!StringUtils.isEmpty(country);
// what about city and state?
boolean hasCityAndState =
!StringUtils.isEmpty(city) && !StringUtils.isEmpty(state);
// what about zipcode ?
boolean hasZipCodeAndCountry = !StringUtils.isEmpty(zipcode) && !StringUtils.isEmpty(country);
// what about just trying city and country?
boolean hasCityAndCountry = !StringUtils.isEmpty(city) && !StringUtils.isEmpty(country);
// fall through if its not empty
boolean hasStreet = !StringUtils.isEmpty(addy);
Geocoder.LatLong latLong = null;
if (hasAllFields) {
latLong = this.googleGeocoder.geocode(String.format("%s, %s, %s, %s", addy, city, state, zipcode));
}
if (latLong == null && hasCityAndState) {
latLong = this.googleGeocoder.geocode(String.format("%s, %s", city, state));
}
if (latLong == null && hasZipCodeAndCountry) {
latLong = this.googleGeocoder.geocode(String.format("%s, %s", zipcode, country));
}
if (latLong == null && hasStreet) {
latLong = this.googleGeocoder.geocode(addy);
}
if (latLong == null && hasCityAndCountry) {
latLong = this.googleGeocoder.geocode(String.format("%s, %s", city, country));
}
return latLong;
}
public abstract RowMapper<Address> addressRowMapper();
public static class Address {
private String city, postalCode, state, country, address;
private Double longitude, latitude;
public Address(String address, String city, String state, String postalCode, String country, Double longitude, Double latitude) {
this.city = city;
this.state = state;
this.country = country;
this.address = address;
this.postalCode = postalCode;
this.latitude = latitude;
this.longitude = longitude;
}
public Double getLongitude() {
return longitude;
}
public Double getLatitude() {
return latitude;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
public String getCountry() {
return country;
}
public String getAddress() {
return address;
}
public String getPostalCode() {
return postalCode;
}
}
}