diff --git a/src/main/java/org/leolo/map/osm/extract/ExtractElement.java b/src/main/java/org/leolo/map/osm/extract/ExtractElement.java index 358e846..739f6ab 100644 --- a/src/main/java/org/leolo/map/osm/extract/ExtractElement.java +++ b/src/main/java/org/leolo/map/osm/extract/ExtractElement.java @@ -1,9 +1,6 @@ package org.leolo.map.osm.extract; -import de.topobyte.osm4j.core.access.DefaultOsmHandler; -import de.topobyte.osm4j.core.access.OsmInputException; -import de.topobyte.osm4j.core.access.OsmIterator; -import de.topobyte.osm4j.core.access.OsmReader; +import de.topobyte.osm4j.core.access.*; import de.topobyte.osm4j.core.model.iface.*; import de.topobyte.osm4j.pbf.seq.PbfReader; import org.apache.commons.cli.*; @@ -168,6 +165,7 @@ public class ExtractElement { System.exit(3); return; } + doSearch(dbFile, af); for(ExtractItem ei:af.getRelation()){ pendingRelations.add(ei.getId()); } @@ -177,7 +175,6 @@ public class ExtractElement { for(ExtractItem ei:af.getNode()){ pendingNodes.add(ei.getId()); } - doSearch(dbFile, af); expandRelations(dbFile, 1); processWay(dbFile); processNode(dbFile); @@ -190,7 +187,62 @@ public class ExtractElement { * @param af The file which defines the action to be performed */ private void doSearch(InputFile dbFile, ActionFile af) throws IOException{ - //Placeholder + if(af.getSearches().isEmpty()){ + return; + } + OsmReader reader = new PbfReader(dbFile.getInputStream(), true); + reader.setHandler(new OsmHandler() { + @Override + public void handle(OsmBounds osmBounds) throws IOException { + + } + + @Override + public void handle(OsmNode osmNode) throws IOException { + for(SearchItem si:af.getSearches()){ + if(si.matchNode(osmNode)){ + log.atInfo().log("Matched Node {}", osmNode.getId()); + ExtractItem ei = new ExtractItem(); + ei.setId(osmNode.getId()); + af.addNode(ei); + } + } + } + + @Override + public void handle(OsmWay osmWay) throws IOException { + for(SearchItem si:af.getSearches()){ + if(si.matchWay(osmWay)){ + log.atInfo().log("Matched Way {}", osmWay.getId()); + ExtractItem ei = new ExtractItem(); + ei.setId(osmWay.getId()); + af.addWay(ei); + } + } + } + + @Override + public void handle(OsmRelation osmRelation) throws IOException { + for(SearchItem si:af.getSearches()){ + if(si.matchRelation(osmRelation)){ + log.atInfo().log("Matched Relation {}", osmRelation.getId()); + ExtractItem ei = new ExtractItem(); + ei.setId(osmRelation.getId()); + af.addRelation(ei); + } + } + } + + @Override + public void complete() throws IOException { + log.atInfo().log("Finish reading the DB file"); + } + }); + try { + reader.read(); + } catch (OsmInputException e) { + log.atError().withThrowable(e).log("Error when reading the input!"); + } } private void processNode(InputFile dbFile) throws IOException{ diff --git a/src/main/java/org/leolo/map/osm/extract/SearchProvider.java b/src/main/java/org/leolo/map/osm/extract/SearchProvider.java new file mode 100644 index 0000000..acbe27b --- /dev/null +++ b/src/main/java/org/leolo/map/osm/extract/SearchProvider.java @@ -0,0 +1,12 @@ +package org.leolo.map.osm.extract; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface SearchProvider { + String[] searchKey(); +} diff --git a/src/main/java/org/leolo/map/osm/extract/SearchProviderManager.java b/src/main/java/org/leolo/map/osm/extract/SearchProviderManager.java new file mode 100644 index 0000000..c4820c8 --- /dev/null +++ b/src/main/java/org/leolo/map/osm/extract/SearchProviderManager.java @@ -0,0 +1,112 @@ +package org.leolo.map.osm.extract; + +import eu.infomas.annotation.AnnotationDetector; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.leolo.map.osm.extract.model.SearchItem; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.*; +import java.util.function.BiConsumer; + +public class SearchProviderManager { + + private static SearchProviderManager instance; + private Logger log = LogManager.getLogger(); + private Hashtable items = new Hashtable<>(); + + public static synchronized SearchProviderManager getInstance(){ + if(instance==null){ + instance = new SearchProviderManager(); + } + return instance; + } + + private SearchProviderManager(){ + AnnotationDetector.TypeReporter reporter = new AnnotationDetector.TypeReporter() { + @Override + public void reportTypeAnnotation(Class annoClass, String clazz) { + log.atDebug().log("Class {} has annotation {}", clazz, annoClass.getName()); + try { + Class typeClass = Class.forName(clazz); + if(SearchItem.class.isAssignableFrom(typeClass)){ + log.atDebug().log("Class {} is an output formatter", clazz); + SearchProvider of = (SearchProvider) typeClass.getAnnotation(SearchProvider.class); + for(String format: of.searchKey()){ + if(items.containsKey(format)){ + log.atWarn().log("Duplicated search type {}. Shared by (at least) {} and {}", + format, + typeClass.getName(), + items.get(format).getName() + ); + }else{ + items.put(format, typeClass); + log.atInfo().log("Registering class {} for search type {}", typeClass, format); + } + } + }else{ + log.atError().log("Class {} does not implements OutputFormat but have annotation @OutputFormatter", clazz); + } + } catch (ClassNotFoundException e) { + log.atError().withThrowable(e).log(e.getMessage()); + } + } + + @Override + public Class[] annotations() { + return new Class[]{SearchProvider.class}; + } + }; + final AnnotationDetector cf = new AnnotationDetector(reporter); + try { + cf.detect(); + } catch (IOException e) { + log.atError().withThrowable(e).log(e.getMessage()); + } + } + + public int size() { + return items.size(); + } + + public boolean isEmpty() { + return items.isEmpty(); + } + + public Enumeration keys() { + return items.keys(); + } + + public boolean containsKey(Object key) { + return items.containsKey(key); + } + + public Class get(Object key) { + return items.get(key); + } + + public Set keySet() { + return items.keySet(); + } + + public void forEach(BiConsumer action) { + items.forEach(action); + } + + public int getOutputFormatterCount(){ + HashSet set = new HashSet<>(); + for(Class clazz:items.values()){ + set.add(clazz); + } + return set.size(); + } + + public int getSearchProviderCount(){ + HashSet set = new HashSet<>(); + for(Class clazz:items.values()){ + set.add(clazz); + } + return set.size(); + } +} diff --git a/src/main/java/org/leolo/map/osm/extract/format/SimpleStringSearchProvider.java b/src/main/java/org/leolo/map/osm/extract/format/SimpleStringSearchProvider.java new file mode 100644 index 0000000..6a6f166 --- /dev/null +++ b/src/main/java/org/leolo/map/osm/extract/format/SimpleStringSearchProvider.java @@ -0,0 +1,24 @@ +package org.leolo.map.osm.extract.format; + +import org.leolo.map.osm.extract.SearchProvider; +import org.leolo.map.osm.extract.model.SearchItem; + +@SearchProvider(searchKey = "name") +public class SimpleStringSearchProvider extends SearchItem { + + private String searchKey; + + @Override + public boolean matchString(String target) { + return searchKey.equalsIgnoreCase(target.strip()); + } + + @Override + public void setSearchKey(String searchKey) { + this.searchKey = searchKey.strip(); + } + + @Override public String toString(){ + return "SimpleString["+searchKey+"]"; + } +} diff --git a/src/main/java/org/leolo/map/osm/extract/model/ActionFile.java b/src/main/java/org/leolo/map/osm/extract/model/ActionFile.java index e5d9f34..4cbea25 100644 --- a/src/main/java/org/leolo/map/osm/extract/model/ActionFile.java +++ b/src/main/java/org/leolo/map/osm/extract/model/ActionFile.java @@ -2,6 +2,7 @@ package org.leolo.map.osm.extract.model; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.leolo.map.osm.extract.SearchProviderManager; import org.leolo.map.osm.extract.util.InputFile; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -9,11 +10,13 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import javax.management.ReflectionException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.util.*; public class ActionFile { @@ -24,6 +27,11 @@ public class ActionFile { private Map way = new Hashtable<>(); private Map node = new Hashtable<>(); + + private String baseLanguage; + private HashSet otherLanguage = new HashSet<>(); + private Vector searches = new Vector<>(); + public ActionFile(InputFile path) throws IOException, SAXException, ParserConfigurationException { log.atInfo().log("Parsing action file"); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); @@ -86,6 +94,42 @@ public class ActionFile { continue; } } + NodeList languages = rootElement.getElementsByTagName("language"); + if(languages.getLength()>0){ + NodeList children = languages.item(0).getChildNodes(); + for(int i=0;i0){ + NodeList searches = searchesNodeList.item(0).getChildNodes(); + for(int i=0;i getOtherLanguage() { + return otherLanguage; + } + + public Vector getSearches() { + return searches; + } } diff --git a/src/main/java/org/leolo/map/osm/extract/model/SearchItem.java b/src/main/java/org/leolo/map/osm/extract/model/SearchItem.java new file mode 100644 index 0000000..9403fe0 --- /dev/null +++ b/src/main/java/org/leolo/map/osm/extract/model/SearchItem.java @@ -0,0 +1,67 @@ +package org.leolo.map.osm.extract.model; + +import de.topobyte.osm4j.core.model.iface.OsmEntity; +import de.topobyte.osm4j.core.model.iface.OsmNode; +import de.topobyte.osm4j.core.model.iface.OsmRelation; +import de.topobyte.osm4j.core.model.iface.OsmWay; + +import java.util.HashSet; +import java.util.Set; + +public abstract class SearchItem { + + private ActionFile af; + + private HashSet tagName = new HashSet<>(); + + public SearchItem(ActionFile af){ + this.af = af; + setTags(); + } + + public SearchItem(){ + //Empty constructor + } + + protected final void setActionFile(ActionFile af){ + this.af = af; + setTags(); + } + + private void setTags(){ + tagName.add("name:"+af.getBaseLanguage()); + for(String lang:af.getOtherLanguage()){ + tagName.add("name:"+lang); + } + } + + public abstract boolean matchString(String target); + public abstract void setSearchKey(String searchKey); + + private boolean matchEntity(OsmEntity entity){ + for(int i=0;i