// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.pgsimple.v0_6.impl;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import org.openstreetmap.osmosis.core.OsmosisRuntimeException;
import org.openstreetmap.osmosis.core.database.DbFeature;
import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
import org.openstreetmap.osmosis.core.domain.v0_6.Tag;
import org.openstreetmap.osmosis.core.lifecycle.ReleasableIterator;
import org.openstreetmap.osmosis.pgsimple.common.BaseDao;
import org.openstreetmap.osmosis.pgsimple.common.DatabaseContext;
import org.openstreetmap.osmosis.pgsimple.common.NoSuchRecordException;
/**
* Provides functionality common to all top level entity daos.
*
* @author Brett Henderson
* @param <T>
* The entity type to be supported.
*/
public abstract class EntityDao<T extends Entity> extends BaseDao {
private EntityFeatureDao<Tag, DbFeature<Tag>> tagDao;
private ActionDao actionDao;
private EntityMapper<T> entityMapper;
private PreparedStatement countStatement;
private PreparedStatement getStatement;
private PreparedStatement insertStatement;
private PreparedStatement updateStatement;
private PreparedStatement deleteStatement;
/**
* Creates a new instance.
*
* @param dbCtx
* The database context to use for accessing the database.
* @param entityMapper
* Provides entity type specific JDBC support.
* @param actionDao
* The dao to use for adding action records to the database.
*/
protected EntityDao(DatabaseContext dbCtx, EntityMapper<T> entityMapper, ActionDao actionDao) {
super(dbCtx);
this.entityMapper = entityMapper;
this.actionDao = actionDao;
tagDao = new EntityFeatureDao<Tag, DbFeature<Tag>>(dbCtx, new TagMapper(entityMapper.getEntityName()));
}
/**
* Checks if the specified entity exists in the database.
*
* @param entityId
* The unique identifier of the entity.
* @return True if the entity exists in the database.
*/
public boolean exists(long entityId) {
if (countStatement == null) {
countStatement = prepareStatement(entityMapper.getSqlSelectCount(true));
}
try {
countStatement.setLong(1, entityId);
try (ResultSet resultSet = countStatement.executeQuery()) {
boolean result;
if (!resultSet.next()) {
throw new OsmosisRuntimeException(
"Entity count query didn't return any rows.");
}
result = resultSet.getLong("count") > 0;
return result;
}
} catch (SQLException e) {
throw new OsmosisRuntimeException(
"Count query failed for "
+ entityMapper.getEntityName() + " " + entityId + ".",
e
);
}
}
/**
* Loads the specified entity from the database.
*
* @param entityId
* The unique identifier of the entity.
* @return The loaded entity.
*/
public T getEntity(long entityId) {
T entity;
if (getStatement == null) {
getStatement = prepareStatement(entityMapper.getSqlSelect(true, true));
}
try {
getStatement.setLong(1, entityId);
try (ResultSet resultSet = getStatement.executeQuery()) {
if (!resultSet.next()) {
throw new NoSuchRecordException(entityMapper.getEntityName()
+ " " + entityId + " doesn't exist.");
}
entity = entityMapper.parseRecord(resultSet);
}
for (DbFeature<Tag> dbTag : tagDao.getAll(entityId)) {
entity.getTags().add(dbTag.getFeature());
}
// Add the type specific features.
loadFeatures(entityId, entity);
return entity;
} catch (SQLException e) {
throw new OsmosisRuntimeException(
"Query failed for "
+ entityMapper.getEntityName() + " " + entityId + ".",
e
);
}
}
/**
* Adds the specified tags to the database.
*
* @param entityId
* The identifier of the entity to add these features to.
* @param tags
* The features to add.
*/
private void addTags(long entityId, Collection<Tag> tags) {
Collection<DbFeature<Tag>> dbList;
dbList = new ArrayList<DbFeature<Tag>>(tags.size());
for (Tag tag : tags) {
dbList.add(new DbFeature<Tag>(entityId, tag));
}
tagDao.addAll(dbList);
}
/**
* Adds the type specific features to the entity.
*
* @param entityId
* The entity id.
* @param entity
* The entity requiring features to be added.
*/
protected abstract void loadFeatures(long entityId, T entity);
/**
* Adds the specified entity to the database.
*
* @param entity
* The entity to add.
*/
public void addEntity(T entity) {
if (insertStatement == null) {
insertStatement = prepareStatement(entityMapper.getSqlInsert(1));
}
try {
entityMapper.populateEntityParameters(insertStatement, 1, entity);
insertStatement.executeUpdate();
} catch (SQLException e) {
throw new OsmosisRuntimeException(
"Insert failed for " + entityMapper.getEntityName()
+ " " + entity.getId() + ".",
e
);
}
addTags(entity.getId(), entity.getTags());
actionDao.addAction(entityMapper.getEntityType(), ChangesetAction.CREATE, entity.getId());
}
/**
* Updates the specified entity details in the database.
*
* @param entity
* The entity to update.
*/
public void modifyEntity(T entity) {
if (updateStatement == null) {
updateStatement = prepareStatement(entityMapper.getSqlUpdate(true));
}
try {
int prmIndex;
prmIndex = 1;
prmIndex = entityMapper.populateEntityParameters(updateStatement, prmIndex, entity);
updateStatement.setLong(prmIndex++, entity.getId());
updateStatement.executeUpdate();
} catch (SQLException e) {
throw new OsmosisRuntimeException(
"Update failed for "
+ entityMapper.getEntityName() + " "
+ entity.getId() + ".",
e
);
}
tagDao.removeList(entity.getId());
addTags(entity.getId(), entity.getTags());
actionDao.addAction(entityMapper.getEntityType(), ChangesetAction.MODIFY, entity.getId());
}
/**
* Removes the specified entity from the database.
*
* @param entityId
* The id of the entity to remove.
*/
public void removeEntity(long entityId) {
int prmIndex;
tagDao.removeList(entityId);
if (deleteStatement == null) {
deleteStatement = prepareStatement(entityMapper.getSqlDelete(true));
}
try {
prmIndex = 1;
deleteStatement.setLong(prmIndex++, entityId);
deleteStatement.executeUpdate();
} catch (SQLException e) {
throw new OsmosisRuntimeException(
"Delete failed for "
+ entityMapper.getEntityName() + " "
+ entityId + ".",
e
);
}
actionDao.addAction(entityMapper.getEntityType(), ChangesetAction.DELETE, entityId);
}
/**
* Returns an iterator providing access to all entities in the database.
*
* @return The entity iterator.
*/
public abstract ReleasableIterator<T> iterate();
}