// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.apidb.v0_6.impl;
import java.util.List;
import org.openstreetmap.osmosis.core.OsmosisRuntimeException;
import org.openstreetmap.osmosis.core.database.DbFeature;
import org.openstreetmap.osmosis.core.database.DbFeatureHistory;
import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
import org.openstreetmap.osmosis.core.domain.v0_6.Tag;
import org.openstreetmap.osmosis.core.lifecycle.ReleasableContainer;
import org.openstreetmap.osmosis.core.lifecycle.ReleasableIterator;
/**
* Provides a single iterator based on data provided by underlying iterators from each of the
* underlying entity and feature iterators. Each underlying iterator provides one component of the
* overall entity.
*
* @param <T>
* The type of entity provided by this iterator.
*/
public class EntityHistoryReader<T extends Entity> implements ReleasableIterator<EntityHistory<T>> {
private ReleasableContainer releasableContainer;
private ReleasableIterator<EntityHistory<T>> entityIterator;
private FeatureHistoryPopulator<T, Tag, ?> tagPopulator;
private List<FeatureHistoryPopulator<T, ?, ?>> featurePopulators;
private EntityHistory<T> nextValue;
/**
* Creates a new instance.
*
* @param entityIterator
* The entity source.
* @param tagIterator
* The tag source.
* @param featurePopulators
* Populators to add entity specific features to the generated entities.
*/
public EntityHistoryReader(ReleasableIterator<EntityHistory<T>> entityIterator,
ReleasableIterator<DbFeatureHistory<DbFeature<Tag>>> tagIterator,
List<FeatureHistoryPopulator<T, ?, ?>> featurePopulators) {
releasableContainer = new ReleasableContainer();
this.entityIterator = releasableContainer.add(entityIterator);
tagPopulator = releasableContainer.add(new FeatureHistoryPopulator<T, Tag, DbFeature<Tag>>(tagIterator,
new TagCollectionLoader<T>()));
for (FeatureHistoryPopulator<T, ?, ?> featurePopulator : featurePopulators) {
releasableContainer.add(featurePopulator);
}
this.featurePopulators = featurePopulators;
}
/**
* Consolidates the output of all history readers so that entities are fully
* populated.
*
* @return An entity history record where the entity is fully populated.
*/
private EntityHistory<T> readNextEntityHistory() {
EntityHistory<T> entityHistory;
T entity;
entityHistory = entityIterator.next();
entity = entityHistory.getEntity();
// Add all applicable tags to the entity.
tagPopulator.populateFeatures(entity);
// Add entity type specific features to the entity.
for (FeatureHistoryPopulator<T, ?, ?> populator : featurePopulators) {
populator.populateFeatures(entity);
}
return entityHistory;
}
/**
* {@inheritDoc}
*/
@Override
public boolean hasNext() {
while (nextValue == null && entityIterator.hasNext()) {
nextValue = readNextEntityHistory();
}
return (nextValue != null);
}
/**
* {@inheritDoc}
*/
@Override
public EntityHistory<T> next() {
EntityHistory<T> result;
if (!hasNext()) {
throw new OsmosisRuntimeException("No records are available, call hasNext first.");
}
result = nextValue;
nextValue = null;
return result;
}
/**
* {@inheritDoc}
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
@Override
public void close() {
releasableContainer.close();
}
}