org.opentripplanner.graph_builder.module.shapefile.JoinedFeatureConverter Maven / Gradle / Ivy
package org.opentripplanner.graph_builder.module.shapefile;
import java.io.IOException;
import java.util.HashMap;
import org.geotools.data.FeatureSource;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opentripplanner.graph_builder.services.shapefile.FeatureSourceFactory;
import org.opentripplanner.graph_builder.services.shapefile.SimpleFeatureConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a simple feature converter that gets features from a secondary feature source. This is
* useful if you have (say) bike lane data in another file.
*/
public class JoinedFeatureConverter implements SimpleFeatureConverter {
private static Logger log = LoggerFactory.getLogger(JoinedFeatureConverter.class);
private SimpleFeatureConverter converter;
private String joinedKey;
private String mainKey;
private FeatureSource joinedSource;
private HashMap cache;
public JoinedFeatureConverter() {
}
public JoinedFeatureConverter(String mainKey, String joinedKey,
SimpleFeatureConverter converter,
FeatureSource joinedSource) {
this.mainKey = mainKey;
this.joinedKey = joinedKey;
this.converter = converter;
this.joinedSource = joinedSource;
}
@Override
public T convert(SimpleFeature feature) {
ensureCached();
String mainKeyValue = toHashableString(feature.getAttribute(this.mainKey));
if (mainKeyValue == null) {
log.warn("Feature " + feature.getID() + " has null value for its mainKey (" + mainKey + ")");
return null;
}
SimpleFeature joinedFeature = cache.get(mainKeyValue);
if (joinedFeature == null) {
return null;
} else {
return converter.convert(joinedFeature);
}
}
/** We have to cache all the features in the supplemental file, because
* if we try to load them on the fly, GeoTools wigs out.
*/
private void ensureCached() {
if (cache != null) {
return;
}
cache = new HashMap();
try {
FeatureCollection features = joinedSource
.getFeatures();
FeatureIterator it = features.features();
while (it.hasNext()) {
SimpleFeature feature = it.next();
String joinedKeyValue = toHashableString(feature.getAttribute(joinedKey));
if (joinedKeyValue != null) {
cache.put(joinedKeyValue, feature);
} else {
log.warn("Feature " + feature.getID() + " has null value for its joinedKey (" + joinedKey + ")");
}
}
it.close();
} catch (IOException e) {
throw new RuntimeException("Could not cache values for joined shapefile", e);
}
}
/**
* Convert a feature value to a String for hashing. We use this instead of simply calling
* toString to avoid issues when the column types for these features are slightly different. See
* http://opentripplanner.org/ticket/226
*
* @param keyValue
* @return a string to use as the hash key
*/
private String toHashableString(Object keyValue) {
if (keyValue == null) {
return null;
}
if (keyValue instanceof Number) {
keyValue = ((Number)keyValue).doubleValue();
}
return keyValue.toString();
}
public void setConverter(SimpleFeatureConverter converter) {
this.converter = converter;
}
/**
* The name of the attribute in the joined feature source to use as the join key.
*/
public void setJoinedKey(String joinedKey) {
this.joinedKey = joinedKey;
}
/**
* The name of the attribute in the main feature source to use as the join key.
*/
public void setMainKey(String mainKey) {
this.mainKey = mainKey;
}
public void setJoinedSourceFactory(FeatureSourceFactory factory) {
this.joinedSource = factory.getFeatureSource();
}
public void setJoinedSource(FeatureSource joinedSource) {
this.joinedSource = joinedSource;
}
}