// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.tagtransform.impl;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer;
import org.openstreetmap.osmosis.core.domain.common.TimestampFormat;
import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
import org.openstreetmap.osmosis.core.domain.v0_6.EntityType;
import org.openstreetmap.osmosis.core.domain.v0_6.Tag;
import org.openstreetmap.osmosis.core.task.common.Task;
import org.openstreetmap.osmosis.core.task.v0_6.Initializable;
import org.openstreetmap.osmosis.tagtransform.Match;
import org.openstreetmap.osmosis.tagtransform.Output;
import org.openstreetmap.osmosis.tagtransform.StatsSaveException;
import org.openstreetmap.osmosis.tagtransform.TTEntityType;
import org.openstreetmap.osmosis.tagtransform.Translation;
import org.openstreetmap.osmosis.xml.common.XmlTimestampFormat;
/**
* Class is intended to provide utility place for tag transform functionality.
* See {@link org.openstreetmap.osmosis.tagtransform.v0_6.TransformTask
* TransformTask} for example implementation.
*
* @author apopov
*
* @param <T>
* is a sink type.
*/
public abstract class TransformHelper<T extends Task & Initializable> implements Initializable {
protected Logger logger = Logger.getLogger(this.getClass().getName());
protected T sink;
protected String statsFile;
protected String configFile;
protected List<Translation> translations;
protected static TimestampFormat timestampFormat = new XmlTimestampFormat();
public TransformHelper(String configFile, String statsFile) {
logger.log(Level.FINE, "Transform configured with " + configFile + " and " + statsFile);
translations = new TransformLoader().load(configFile);
this.statsFile = statsFile;
this.configFile = configFile;
}
@Override
public void initialize(Map<String, Object> metaData) {
sink.initialize(metaData);
}
public void setSink(T sink) {
this.sink = sink;
}
@Override
public void complete() {
if (statsFile != null && !statsFile.isEmpty()) {
StringBuilder builder = new StringBuilder();
builder.append(configFile);
builder.append("\n\n");
for (Translation t : translations) {
t.outputStats(builder, "");
}
Writer writer = null;
try {
writer = new FileWriter(new File(statsFile));
writer.write(builder.toString());
} catch (IOException e) {
throw new StatsSaveException("Failed to save stats: " + e.getLocalizedMessage(), e);
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
logger.log(Level.WARNING, "Unable to close stats file " + statsFile + ".", e);
}
}
}
}
sink.complete();
}
@Override
public void close() {
sink.close();
}
/**
* Transforms entity container according to configFile.
*
* @param entityContainer
* The entity to be processed.
* @return transformed (if needed) entityContainer
*/
protected EntityContainer processEntityContainer(EntityContainer entityContainer) {
// Entities may have been made read-only at some point in the pipeline.
// We want a writeable instance so that we can update the tags.
EntityContainer writeableEntityContainer = entityContainer.getWriteableInstance();
Entity entity = entityContainer.getEntity();
Collection<Tag> entityTags = entity.getTags();
EntityType entityType = entity.getType();
// Store the tags in a map keyed by tag key.
Map<String, String> tagMap = new HashMap<String, String>();
for (Tag tag : entity.getTags()) {
tagMap.put(tag.getKey(), tag.getValue());
}
// Apply tag transformations.
for (Translation translation : translations) {
Collection<Match> matches = translation.match(tagMap, TTEntityType.fromEntityType06(entityType), entity
.getUser().getName(), entity.getUser().getId());
if (matches == null || matches.isEmpty()) {
continue;
}
if (translation.isDropOnMatch()) {
return null;
}
Map<String, String> newTags = new HashMap<String, String>();
for (Output output : translation.getOutputs()) {
output.apply(tagMap, newTags, matches);
}
tagMap = newTags;
}
// Replace the entity tags with the transformed values.
entityTags.clear();
for (Entry<String, String> tag : tagMap.entrySet()) {
entityTags.add(new Tag(tag.getKey(), tag.getValue()));
}
return writeableEntityContainer;
}
}