1 package net.sourceforge.jgeocoder.tiger; 2 import static net.sourceforge.jgeocoder.AddressComponent.CITY; 3 import static net.sourceforge.jgeocoder.AddressComponent.COUNTY; 4 import static net.sourceforge.jgeocoder.AddressComponent.LAT; 5 import static net.sourceforge.jgeocoder.AddressComponent.LON; 6 import static net.sourceforge.jgeocoder.AddressComponent.STATE; 7 import static net.sourceforge.jgeocoder.AddressComponent.ZIP; 8 9 import java.io.File; 10 import java.util.Map; 11 12 import net.sourceforge.jgeocoder.AddressComponent; 13 14 import org.apache.commons.lang.StringUtils; 15 import org.apache.commons.lang.builder.EqualsBuilder; 16 import org.apache.commons.lang.builder.HashCodeBuilder; 17 import org.apache.commons.lang.builder.ToStringBuilder; 18 import org.apache.commons.logging.Log; 19 import org.apache.commons.logging.LogFactory; 20 21 import com.sleepycat.je.DatabaseException; 22 import com.sleepycat.je.Environment; 23 import com.sleepycat.je.EnvironmentConfig; 24 import com.sleepycat.persist.EntityStore; 25 import com.sleepycat.persist.PrimaryIndex; 26 import com.sleepycat.persist.SecondaryIndex; 27 import com.sleepycat.persist.StoreConfig; 28 import com.sleepycat.persist.model.Entity; 29 import com.sleepycat.persist.model.KeyField; 30 import com.sleepycat.persist.model.Persistent; 31 import com.sleepycat.persist.model.PrimaryKey; 32 import com.sleepycat.persist.model.Relationship; 33 import com.sleepycat.persist.model.SecondaryKey; 34 35 @Entity 36 class CityWithSpaces{ 37 @PrimaryKey 38 private String _noSpace; 39 private String _withSpace; 40 public String getNoSpace() { 41 return _noSpace; 42 } 43 public String getWithSpace() { 44 return _withSpace; 45 } 46 public void setNoSpace(String noSpace) { 47 _noSpace = noSpace; 48 } 49 public void setWithSpace(String withSpace) { 50 _withSpace = withSpace; 51 } 52 @Override 53 public String toString() { 54 return ToStringBuilder.reflectionToString(this); 55 } 56 @Override 57 public int hashCode() { 58 return HashCodeBuilder.reflectionHashCode(this); 59 } 60 @Override 61 public boolean equals(Object obj) { 62 return EqualsBuilder.reflectionEquals(this, obj); 63 } 64 } 65 66 @Entity 67 class CityStateGeo{ 68 @PrimaryKey 69 private Location _location; 70 private float _lat; 71 private float _lon; 72 public Location getLocation() { 73 return _location; 74 } 75 public void setLocation(Location location) { 76 _location = location; 77 } 78 public float getLat() { 79 return _lat; 80 } 81 public void setLat(float lat) { 82 _lat = lat; 83 } 84 public float getLon() { 85 return _lon; 86 } 87 public void setLon(float lon) { 88 _lon = lon; 89 } 90 @Override 91 public String toString() { 92 return ToStringBuilder.reflectionToString(this); 93 } 94 @Override 95 public int hashCode() { 96 return HashCodeBuilder.reflectionHashCode(this); 97 } 98 @Override 99 public boolean equals(Object obj) { 100 return EqualsBuilder.reflectionEquals(this, obj); 101 } 102 } 103 104 @Entity 105 class County{ 106 @PrimaryKey 107 private Location _location; 108 private String[] _zips; 109 private float _lat; 110 private float _lon; 111 public Location getLocation() { 112 return _location; 113 } 114 public void setLocation(Location _location) { 115 this._location = _location; 116 } 117 public String[] getZips() { 118 return _zips; 119 } 120 public void setZips(String[] _zips) { 121 this._zips = _zips; 122 } 123 public float getLat() { 124 return _lat; 125 } 126 public void setLat(float _lat) { 127 this._lat = _lat; 128 } 129 public float getLon() { 130 return _lon; 131 } 132 public void setLon(float _lon) { 133 this._lon = _lon; 134 } 135 @Override 136 public String toString() { 137 return ToStringBuilder.reflectionToString(this); 138 } 139 @Override 140 public int hashCode() { 141 return HashCodeBuilder.reflectionHashCode(this); 142 } 143 @Override 144 public boolean equals(Object obj) { 145 return EqualsBuilder.reflectionEquals(this, obj); 146 } 147 } 148 149 @Entity 150 class ZipCode{ 151 @PrimaryKey 152 private String _zip; 153 @SecondaryKey(relate=Relationship.MANY_TO_ONE) 154 private Location _location; 155 @SecondaryKey(relate=Relationship.MANY_TO_ONE) 156 private String _county; 157 private float _lat; 158 private float _lon; 159 private String _zipClass; 160 public String getZip() { 161 return _zip; 162 } 163 public void setZip(String zip) { 164 _zip = zip; 165 } 166 public Location getLocation() { 167 return _location; 168 } 169 public void setLocation(Location location) { 170 _location = location; 171 } 172 public String getCounty() { 173 return _county; 174 } 175 public void setCounty(String county) { 176 _county = county; 177 } 178 public float getLat() { 179 return _lat; 180 } 181 public void setLat(float lat) { 182 _lat = lat; 183 } 184 public float getLon() { 185 return _lon; 186 } 187 public void setLon(float lon) { 188 _lon = lon; 189 } 190 public String getZipClass() { 191 return _zipClass; 192 } 193 public void setZipClass(String zipClass) { 194 _zipClass = zipClass; 195 } 196 @Override 197 public String toString() { 198 return ToStringBuilder.reflectionToString(this); 199 } 200 @Override 201 public int hashCode() { 202 return HashCodeBuilder.reflectionHashCode(this); 203 } 204 @Override 205 public boolean equals(Object obj) { 206 return EqualsBuilder.reflectionEquals(this, obj); 207 } 208 209 } 210 @Persistent 211 class Location{ 212 @KeyField(1) 213 private String _city; 214 @KeyField(2) 215 private String _state; 216 217 public String getCity() { 218 return _city; 219 } 220 public void setCity(String city) { 221 _city = city; 222 } 223 public String getState() { 224 return _state; 225 } 226 public void setState(String state) { 227 _state = state; 228 } 229 @Override 230 public String toString() { 231 return ToStringBuilder.reflectionToString(this); 232 } 233 @Override 234 public int hashCode() { 235 return HashCodeBuilder.reflectionHashCode(this); 236 } 237 @Override 238 public boolean equals(Object obj) { 239 return EqualsBuilder.reflectionEquals(this, obj); 240 } 241 } 242 /*** 243 * TODO javadocs me 244 * @author jliang 245 * 246 */ 247 class ZipCodeDAO{ 248 private static final Log LOGGER = LogFactory.getLog(ZipCodeDAO.class); 249 private PrimaryIndex<String, ZipCode> _zipCodeByZip; 250 private SecondaryIndex<Location, String, ZipCode> _zipCodeByLocation; 251 private PrimaryIndex<Location, CityStateGeo> _cityStateGeoByLocation; 252 private PrimaryIndex<String, CityWithSpaces> _cityWithSpaceByNoSpace; 253 private PrimaryIndex<Location, County> _countyByLocation; 254 public ZipCodeDAO(EntityStore store) throws DatabaseException{ 255 _zipCodeByZip = store.getPrimaryIndex(String.class, ZipCode.class); 256 _zipCodeByLocation = store.getSecondaryIndex(_zipCodeByZip, Location.class, "_location"); 257 _cityStateGeoByLocation = store.getPrimaryIndex(Location.class, CityStateGeo.class); 258 _cityWithSpaceByNoSpace = store.getPrimaryIndex(String.class, CityWithSpaces.class); 259 _countyByLocation = store.getPrimaryIndex(Location.class, County.class); 260 } 261 262 public PrimaryIndex<Location, County> getCountyByLocation() { 263 return _countyByLocation; 264 } 265 266 public PrimaryIndex<String, CityWithSpaces> getCityWithSpaceByNoSpace() { 267 return _cityWithSpaceByNoSpace; 268 } 269 270 public PrimaryIndex<Location, CityStateGeo> getCityStateGeoByLocation() { 271 return _cityStateGeoByLocation; 272 } 273 public SecondaryIndex<Location, String, ZipCode> getZipCodeByLocation() { 274 return _zipCodeByLocation; 275 } 276 public PrimaryIndex<String, ZipCode> getZipCodeByZip() { 277 return _zipCodeByZip; 278 } 279 280 public boolean fillInCSByZip(Map<AddressComponent, String> m, String zip) throws DatabaseException{ 281 return fillInCSByZip(m, _zipCodeByZip.get(zip)); 282 } 283 284 private boolean fillInCSByZip(Map<AddressComponent, String> m, ZipCode zipcode) throws DatabaseException{ 285 if(zipcode == null){ 286 return false; 287 } 288 String city = zipcode.getLocation().getCity(); 289 CityWithSpaces cws = getCityWithSpaceByNoSpace().get(city); 290 if(cws != null){ 291 m.put(CITY, cws.getWithSpace()); 292 }else{ 293 m.put(CITY, city); 294 } 295 m.put(COUNTY, zipcode.getCounty()); 296 m.put(STATE, zipcode.getLocation().getState()); 297 return true; 298 } 299 300 private County getCounty(Location loc){ 301 try { 302 return _countyByLocation.get(loc); 303 } catch (DatabaseException e) { 304 if(LOGGER.isDebugEnabled()){ 305 LOGGER.debug("Unable to get county by city state", e); 306 } 307 return null; 308 } 309 } 310 311 public County getCounty(String city, String state){ 312 if(StringUtils.isBlank(city)||StringUtils.isBlank(state)){ 313 return null; 314 } 315 city = city.replaceAll("//s+|//bCOUNTY$|//bPARISH$|//bBOROUGH$", ""); 316 Location loc = new Location(); 317 loc.setCity(city); loc.setState(state); 318 return getCounty(loc); 319 } 320 321 public boolean geocodeByCityState(Map<AddressComponent, String> m){ 322 String city = m.get(AddressComponent.CITY), state = m.get(AddressComponent.STATE); 323 if(StringUtils.isBlank(city)||StringUtils.isBlank(state)){ 324 return false; 325 } 326 boolean onlyCounty = city.endsWith("COUNTY"); 327 city = city.replaceAll("//s+|//bCOUNTY$|//bPARISH$|//bBOROUGH$", ""); 328 try { 329 Location loc = new Location(); 330 loc.setCity(city); loc.setState(state); 331 CityStateGeo geo = onlyCounty? null : _cityStateGeoByLocation.get(loc); 332 County county = getCounty(loc); 333 if(geo!= null || county != null){ 334 if(onlyCounty && county != null){ 335 m.put(LAT, String.valueOf(county.getLat())); 336 m.put(LON, String.valueOf(county.getLon())); 337 return true; 338 }else if(geo != null){ 339 m.put(LAT, String.valueOf(geo.getLat())); 340 m.put(LON, String.valueOf(geo.getLon())); 341 return true; 342 }else if(county != null){ 343 m.put(LAT, String.valueOf(county.getLat())); 344 m.put(LON, String.valueOf(county.getLon())); 345 return true; 346 } 347 } 348 } catch (DatabaseException e) { 349 if(LOGGER.isDebugEnabled()){ 350 LOGGER.debug("Unable to geocode with city state", e); 351 } 352 return false; 353 } 354 return false; 355 } 356 357 public boolean geocodeByZip(Map<AddressComponent, String> m){ 358 String zip = m.get(ZIP); 359 if(StringUtils.isBlank(zip)){ 360 return false; 361 } 362 try { 363 ZipCode zipcode = _zipCodeByZip.get(zip); 364 if(zipcode != null){ 365 if(m.get(LAT) == null){ 366 m.put(LAT, String.valueOf(zipcode.getLat())); 367 } 368 if(m.get(LON) == null){ 369 m.put(LON, String.valueOf(zipcode.getLon())); 370 } 371 return true; 372 } 373 } catch (Exception e) { 374 if(LOGGER.isDebugEnabled()){ 375 LOGGER.debug("Unable to geocode with zip", e); 376 } 377 return false; 378 } 379 return false; 380 } 381 } 382 383 class ZipCodesDb{ 384 private Environment _env = null; 385 private EntityStore _store = null; 386 public Environment getEnv() { 387 return _env; 388 } 389 public EntityStore getStore() { 390 return _store; 391 } 392 393 public void init(JGeocoderConfig jgconfig, File envHome, boolean readOnly, boolean transactional) throws DatabaseException{ 394 395 EnvironmentConfig config = new EnvironmentConfig(); 396 config.setAllowCreate(!readOnly); 397 config.setReadOnly(readOnly); 398 config.setTransactional(transactional); 399 if(jgconfig != null){ 400 if(jgconfig.getBerkeleyDbCachePercent() >= 0 ){ 401 config.setCacheSize(jgconfig.getBerkeleyDbCacheSize()); 402 } 403 if(jgconfig.getBerkeleyDbCachePercent() >= 0){ 404 config.setCachePercent(jgconfig.getBerkeleyDbCachePercent()); 405 } 406 } 407 _env = new Environment(envHome, config); 408 StoreConfig config2 = new StoreConfig(); 409 config2.setAllowCreate(!readOnly); 410 config2.setReadOnly(readOnly); 411 config2.setTransactional(transactional); 412 _store = new EntityStore(_env, "ZipCodeEntityStore", config2); 413 } 414 415 public void init(File envHome, boolean readOnly, boolean transactional) throws DatabaseException{ 416 init(null, envHome, readOnly, transactional); 417 } 418 419 public void shutdown() throws DatabaseException{ 420 if(_store != null){ 421 _store.close(); 422 } 423 if(_env != null){ 424 _env.close(); 425 } 426 } 427 428 }