/*******************************************************************************
* 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.domain.repository;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.PersistenceException;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;
import com.gisgraphy.domain.geoloc.entity.Adm;
import com.gisgraphy.domain.geoloc.entity.City;
import com.gisgraphy.domain.geoloc.entity.GisFeature;
import com.gisgraphy.domain.geoloc.entity.ZipCode;
import com.gisgraphy.domain.valueobject.SRID;
import com.vividsolutions.jts.geom.Point;
/**
* A data access object for {@link Adm}
*
* @author <a href="mailto:david.masclet@gisgraphy.com">David Masclet</a>
*/
@Repository
public class AdmDao extends GenericGisDao<Adm> implements IAdmDao {
public AdmDao() {
super(Adm.class);
}
@Override
public Adm get(final Long id) {
Assert.notNull(id, "Can not retrieve an Ogject with a null id");
Adm returnValue = null;
try {
return (Adm) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "from "
+ persistentClass.getSimpleName()
+ " o where o.id=" + id;
Query qry = session.createQuery(queryString);
qry.setCacheable(true);
return (Adm) qry.uniqueResult();
}
});
} catch (Exception e) {
logger.info("could not retrieve object of type "
+ persistentClass.getSimpleName() + " with id " + id, e);
}
return returnValue;
}
/**
* Check that codes are consistent according the level (see
* {@link Adm#isConsistentForLevel() } and save it in the datastore
*
* @param adm
* The Adm to save
* @return the saved instance
* @see Adm#isConsistentForLevel()
*/
@Override
public Adm save(Adm adm) {
/*if (!adm.isConsistentForLevel()) {
throw new RuntimeException(
"Level and AdmXCode are inconsistant for " + adm.toString());
}*/
// it is useless to check admCodes because the admCode were a Geonames notion and we will
//soon migrate to OSM.
return super.save(adm);
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAdm1(java.lang.String,
* java.lang.String)
*/
public Adm getAdm1(final String countryCode, final String adm1Code) {
Assert.notNull(countryCode);
Assert.notNull(adm1Code);
return (Adm) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a.countryCode = ? and a.adm1Code= ? and a.level=1";
Query qry = session.createQuery(queryString);
qry.setCacheable(true);
qry.setParameter(0, countryCode.toUpperCase());
qry.setParameter(1, adm1Code);
Adm result = (Adm) qry.uniqueResult();
return result;
}
});
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAdm2(java.lang.String,
* java.lang.String, java.lang.String)
*/
public Adm getAdm2(final String countryCode, final String adm1Code,
final String adm2Code) {
Assert.notNull(countryCode);
Assert.notNull(adm1Code);
Assert.notNull(adm2Code);
return (Adm) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a.countryCode=? and a.adm2Code=?";
if (!"00".equals(adm1Code)) {
queryString += "and a.adm1Code= ?";
}
queryString += " and a.level=2";
Query qry = session.createQuery(queryString);
qry.setCacheable(true);
qry.setParameter(0, countryCode.toUpperCase());
qry.setParameter(1, adm2Code);
if (!"00".equals(adm1Code)) {
qry.setParameter(2, adm1Code);
}
Adm result;
try {
result = (Adm) qry.uniqueResult();
} catch (HibernateException e) {
if (!"00".equals(adm1Code)) {
throw e;
} else {
logger
.error("Can not retrieve Adm for countrycode="
+ countryCode
+ " and adm2code="
+ adm2Code
+ " in flex mode : result is ambiguous");
return null;
}
}
return result;
}
});
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAdm3(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String)
*/
public Adm getAdm3(final String countryCode, final String adm1Code,
final String adm2Code, final String adm3Code) {
Assert.notNull(countryCode);
Assert.notNull(adm1Code);
Assert.notNull(adm2Code);
Assert.notNull(adm3Code);
return (Adm) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a.countryCode=? and a.adm2Code=? and a.adm3Code=?";
if (!"00".equals(adm1Code)) {
queryString += "and a.adm1Code= ?";
}
queryString += " and a.level=3";
Query qry = session.createQuery(queryString);
qry.setCacheable(true);
qry.setParameter(0, countryCode.toUpperCase());
qry.setParameter(1, adm2Code);
qry.setParameter(2, adm3Code);
if (!"00".equals(adm1Code)) {
qry.setParameter(3, adm1Code);
}
Adm result;
try {
result = (Adm) qry.uniqueResult();
} catch (HibernateException e) {
if (!"00".equals(adm1Code)) {
throw e;
} else {
logger
.error("Can not retrieve Adm for countrycode="
+ countryCode
+ " and adm2code="
+ adm2Code
+ " and adm3code="
+ adm3Code
+ " in flex mode : result is ambiguous");
return null;
}
}
return result;
}
});
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAdm4(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String)
*/
public Adm getAdm4(final String countryCode, final String adm1Code,
final String adm2Code, final String adm3Code, final String adm4Code) {
Assert.notNull(countryCode);
Assert.notNull(adm1Code);
Assert.notNull(adm2Code);
Assert.notNull(adm3Code);
Assert.notNull(adm4Code);
return (Adm) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a.countryCode=? and a.adm2Code=? and a.adm3Code=? and a.adm4Code=?";
if (!"00".equals(adm1Code)) {
queryString += "and a.adm1Code= ?";
}
queryString += " and a.level=4";
Query qry = session.createQuery(queryString);
qry.setCacheable(true);
qry.setParameter(0, countryCode.toUpperCase());
qry.setParameter(1, adm2Code);
qry.setParameter(2, adm3Code);
qry.setParameter(3, adm4Code);
if (!"00".equals(adm1Code)) {
qry.setParameter(4, adm1Code);
}
Adm result;
try {
result = (Adm) qry.uniqueResult();
} catch (HibernateException e) {
if (!"00".equals(adm1Code)) {
throw e;
} else {
logger
.error("Can not retrieve Adm for countrycode="
+ countryCode
+ " and adm2code="
+ adm2Code
+ " and adm3code="
+ adm3Code
+ " and adm4code="
+ adm4Code
+ " in flex mode : result is ambiguous");
return null;
}
}
return result;
}
});
}
private boolean isAdmCodeEmpty(String admCode) {
if (admCode == null || admCode.trim().equals("")) {
return true;
}
return false;
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAdm(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String)
*/
public Adm getAdm(final String countryCode, final String adm1Code,
final String adm2Code, final String adm3Code, final String adm4Code) {
Assert.notNull(countryCode);
if (!isAdmCodeEmpty(countryCode)) {
if (!isAdmCodeEmpty(adm1Code)) {
if (!isAdmCodeEmpty(adm2Code)) {
if (!isAdmCodeEmpty(adm3Code)) {
if (!isAdmCodeEmpty(adm4Code)) {
// adm1,adm2,adm3,adm4
return getAdm4(countryCode, adm1Code, adm2Code,
adm3Code, adm4Code);
} else {
// adm1,adm2,adm3,null
return getAdm3(countryCode, adm1Code, adm2Code,
adm3Code);
}
} else {
// adm1,Adm2, null..
return getAdm2(countryCode, adm1Code, adm2Code);
}
} else {
// adm1,null...
return getAdm1(countryCode, adm1Code);
}
} else {
logger.info("Can not retrieve an adm if Adm1code is null");
// if adm1 is empty can not retrieve any Adm
return null;
}
} else {
return null;
}
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getUnused()
*/
@SuppressWarnings("unchecked")
public List<Adm> getUnused() {
return (List<Adm>) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(final Session session)
throws PersistenceException {
final String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a not in (select distinct(g.adm) from GisFeature g)";
final Query qry = session.createQuery(queryString);
qry.setCacheable(true);
List<Adm> result = qry.list();
if (result == null) {
result = new ArrayList<Adm>();
}
return result;
}
});
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.GenericGisDao#getDirty()
*/
@Override
@SuppressWarnings("unchecked")
public List<Adm> getDirties() {
return (List<Adm>) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(final Session session)
throws PersistenceException {
final String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a.featureId < 0";
final Query qry = session.createQuery(queryString);
qry.setCacheable(true);
List<Adm> result = qry.list();
if (result == null) {
result = new ArrayList<Adm>();
}
return result;
}
});
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAllbyLevel(java.lang.Integer)
*/
@SuppressWarnings("unchecked")
public List<Adm> getAllbyLevel(final int level) {
return (List<Adm>) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(final Session session)
throws PersistenceException {
final String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a.level=?";
final Query qry = session.createQuery(queryString);
qry.setCacheable(true);
qry.setParameter(0, level);
List<Adm> result = qry.list();
if (result == null) {
result = new ArrayList<Adm>();
}
return result;
}
});
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#countByLevel(int)
*/
public long countByLevel(final int level) {
// level is of type int =>could not be null
return ((Long) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "select count(*) from "
+ Adm.class.getSimpleName()
+ " a where a.level=? ";
Query qry = session.createQuery(queryString);
qry.setCacheable(true);
qry.setParameter(0, level);
Long result = (Long) qry.uniqueResult();
return result;
}
})).longValue();
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAdmByCountryAndCodeAndLevel(java.lang.String,
* java.lang.String, int)
*/
@SuppressWarnings("unchecked")
public List<Adm> getAdmByCountryAndCodeAndLevel(final String countryCode,
final String admCode, final int level) {
Assert.notNull(countryCode);
Assert.notNull(admCode);
// level is a int =>can not be null
return (List<Adm>) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "from "
+ Adm.class.getSimpleName()
+ " as a where a.countryCode= ? and a.adm"
+ level + "Code = ? and a.level=?";
Query qry = session.createQuery(queryString);
qry.setCacheable(true);
qry.setParameter(0, countryCode.toUpperCase());
qry.setParameter(1, admCode);
qry.setParameter(2, level);
List<Adm> result = (List<Adm>) qry.list();
if (result == null) {
return new ArrayList<Adm>();
}
return result;
}
});
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#getAdmOrFirstValidParentIfNotFound(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String)
*/
public Adm getAdmOrFirstValidParentIfNotFound(final String countryCode,
final String adm1Code, final String adm2Code,
final String adm3Code, final String adm4Code) {
Assert.notNull(countryCode);
Adm adm = null;
String adm1CodeTemp = adm1Code;
String adm2CodeTemp = adm2Code;
String adm3CodeTemp = adm3Code;
String adm4CodeTemp = adm4Code;
do {
adm = getAdm(countryCode, adm1CodeTemp, adm2CodeTemp, adm3CodeTemp,
adm4CodeTemp);
if (adm == null) {
// downgrade the admvalue to search a lower level
if (adm4CodeTemp != null) {
adm4CodeTemp = null;
continue;
} else if (adm3CodeTemp != null) {
adm3CodeTemp = null;
continue;
} else if (adm2CodeTemp != null) {
adm2CodeTemp = null;
continue;
} else {
return getAdm1(countryCode, adm1Code);
}
} else {
return adm;
}
} while (adm == null);
return adm;
}
/*
* (non-Javadoc)
*
* @see com.gisgraphy.domain.repository.IAdmDao#suggestMostAccurateAdm(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String, com.gisgraphy.domain.geoloc.entity.GisFeature)
*/
public Adm suggestMostAccurateAdm(String countryCode, String adm1Code,
String adm2Code, String adm3Code, String adm4Code,
GisFeature gisfeature) {
Assert.notNull(countryCode);
logger.debug("try to find ADM for " + adm1Code + "." + adm2Code + "."
+ adm3Code + "." + adm4Code);
Adm adm = getAdm(countryCode.toUpperCase(), adm1Code, adm2Code,
adm3Code, adm4Code);
if (adm == null) {
// must get the most accurate adm
String lowestNotNullAdmCode = getLowestNotNullAdmCode(adm1Code,
adm2Code, adm3Code, adm4Code);
int level = Adm.getProcessedLevelFromCodes(adm1Code, adm2Code,
adm3Code, adm4Code);
if (lowestNotNullAdmCode != null && level != 0) {
List<Adm> levelAdms = getAdmByCountryAndCodeAndLevel(
countryCode.toUpperCase(), lowestNotNullAdmCode, level);
Adm levelAdm = null;
if (levelAdms.size() == 1) {
levelAdm = levelAdms.get(0);
}
Adm nearestParentAdm = getAdmOrFirstValidParentIfNotFound(
countryCode.toUpperCase(), adm1Code, adm2Code,
adm3Code, adm4Code);
if (levelAdm != null) {
if (nearestParentAdm != null) {
if (((level - nearestParentAdm.getLevel()) <= 2)) {
// the admcode of the lowestlevel is probably not
// well set, return the specified level Adm
logger.warn("[wrong adm" + (level - 1)
+ "code] : The adm" + (level - 1)
+ "Code for " + gisfeature + "[" + adm1Code
+ "." + adm2Code + "." + adm3Code + "."
+ adm4Code
+ "] is wrong. Please correct it to "
+ levelAdm);
return levelAdm;
} else {
logger
.warn("[wrong adm codes] : "
+ ((level - nearestParentAdm
.getLevel()) - 1)
+ " admCodes are wrong for "
+ gisfeature
+ "["
+ adm1Code
+ "."
+ adm2Code
+ "."
+ adm3Code
+ "."
+ adm4Code
+ "] but the adm"
+ level
+ "code is corect. The suggested Adm is "
+ nearestParentAdm);
return nearestParentAdm;
}
} else {
logger.error("[Wrong adm codes] an Adm" + level
+ " exists but no parent for " + adm1Code + "."
+ adm2Code + "." + adm3Code + "." + adm4Code
+ " : all the code before adm" + level
+ " are wrong");
return levelAdm;
}
} else {
// there is no adm with this code for this level, we return
// the nearest parent
// split logs
if ((nearestParentAdm != null)
&& ((level - nearestParentAdm.getLevel()) == 1)) {
logger
.warn("[wrong adm"
+ level
+ "Code] The adm"
+ (level)
+ "Code for "
+ gisfeature
+ "["
+ adm1Code
+ "."
+ adm2Code
+ "."
+ adm3Code
+ "."
+ adm4Code
+ "] is not well set. The nearest parent found is "
+ nearestParentAdm);
} else {
logger
.warn("[wrong adm codes] The adm"
+ (level)
+ "Code for "
+ gisfeature
+ "["
+ adm1Code
+ "."
+ adm2Code
+ "."
+ adm3Code
+ "."
+ adm4Code
+ "] is not well set and some others. The nearest parent found is "
+ nearestParentAdm);
}
return nearestParentAdm;
}
} else {
// The specified adm code doesn't allow a search
logger.warn("No adm can be found for [" + adm1Code + "."
+ adm2Code + "." + adm3Code + "." + adm4Code + "]");
return null;
}
} else {
return adm;
}
}
public int deleteAllByLevel(final int level) {
return ((Integer) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
String queryString = "delete from "
+ persistentClass.getSimpleName()
+ " as a where a.level=?";
Query qry = session.createQuery(queryString);
qry.setParameter(0, level);
qry.setCacheable(false);
return Integer.valueOf(qry.executeUpdate());
}
})).intValue();
}
private String getLowestNotNullAdmCode(String adm1Code, String adm2Code,
String adm3Code, String adm4Code) {
if (!isAdmCodeEmpty(adm1Code)) {
if (!isAdmCodeEmpty(adm2Code)) {
if (!isAdmCodeEmpty(adm3Code)) {
if (!isAdmCodeEmpty(adm4Code)) {
// adm1,adm2,adm3,adm4
return adm4Code;
} else {
// adm1,adm2,adm3,null
return adm3Code;
}
} else {
// adm1,Adm2, null..
return adm2Code;
}
} else {
// adm1,null...
return adm1Code;
}
} else {
// if adm1 is empty can not retrieve any Adm
return null;
}
}
@SuppressWarnings("unchecked")
public List<Long> listFeatureIdByLevel(final int level) {
return ((List<Long>) this.getHibernateTemplate().execute(
new HibernateCallback() {
public Object doInHibernate(final Session session)
throws PersistenceException {
final String queryString = "select featureId from "
+ persistentClass.getSimpleName()
+ " as a where a.level=?";
final Query qry = session.createQuery(queryString);
qry.setParameter(0, level);
qry.setCacheable(false);
return qry.list();
}
}));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public List<Adm> ListByShape(final Point location,final String countryCode) {
Assert.notNull(location);
return (List<Adm>) this.getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session)
throws PersistenceException {
//select name,municipality,source,openstreetmapid from city c
//where st_contains(c.shape,ST_GeometryFromText('POINT(2.349 48.868)',4326))=true limit 1
String pointAsString = "ST_GeometryFromText('POINT("+location.getX()+" "+location.getY()+")',"+SRID.WGS84_SRID.getSRID()+")";
String queryString = "from " + persistentClass.getSimpleName()
+ " as a where st_contains(a.shape,"+pointAsString+")=true ";
;
if (countryCode!=null ){
queryString+=" and a.countryCode='"+countryCode+"'";
}
queryString = queryString+ " order by st_area(a.shape) desc";
Query qry = session.createQuery(queryString);
//qry.setParameter("point2", location);
List<Adm> result = (List<Adm>) qry.list();
if (result == null) {
return new ArrayList<Adm>();
}
return result;
}
});
}
}