// JOSM tag2link plugin.
// Copyright (C) 2011-2012 Don-vip & FrViPofm
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package org.openstreetmap.josm.plugins.tag2link.io;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import org.openstreetmap.josm.io.UTFInputStreamReader;
import org.openstreetmap.josm.plugins.tag2link.Tag2LinkConstants;
import org.openstreetmap.josm.plugins.tag2link.data.Condition;
import org.openstreetmap.josm.plugins.tag2link.data.Link;
import org.openstreetmap.josm.plugins.tag2link.data.LinkPost;
import org.openstreetmap.josm.plugins.tag2link.data.Rule;
import org.openstreetmap.josm.plugins.tag2link.data.Source;
/**
* Class allowing to read the sources file.
* @author Don-vip
*
*/
public class SourcesReader implements Tag2LinkConstants {
XMLStreamReader parser;
/**
* Constructs a new {@code SourcesReader}.
* @param parser The XML parser
*/
public SourcesReader(XMLStreamReader parser) {
this.parser = parser;
}
/**
* Reads the sources and replies them as a {@code Collection}.
* @return The colleciton of sources.
*/
public static Collection<Source> readSources() {
List<Source> result = new ArrayList<>();
try {
InputStream is = SourcesReader.class.getResourceAsStream(XML_LOCATION);
InputStreamReader ir = UTFInputStreamReader.create(is, UTF8_ENCODING);
XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(ir);
result.addAll(new SourcesReader(parser).parseDoc());
} catch (IOException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
} catch (FactoryConfigurationError e) {
e.printStackTrace();
}
return result;
}
/**
* When cursor is at the start of an element, moves it to the end tag of that element.
* Nested content is skipped.
*
* This is basically the same code as parseUnkown(), except for the warnings, which
* are displayed for inner elements and not at top level.
*/
private void jumpToEnd(boolean printWarning) throws XMLStreamException {
while (true) {
int event = parser.next();
if (event == XMLStreamConstants.START_ELEMENT) {
parseUnknown(printWarning);
} else if (event == XMLStreamConstants.END_ELEMENT) {
return;
}
}
}
private void jumpToEnd() throws XMLStreamException {
jumpToEnd(true);
}
protected void parseUnknown() throws XMLStreamException {
parseUnknown(true);
}
protected void parseUnknown(boolean printWarning) throws XMLStreamException {
if (printWarning) {
System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", parser.getLocalName()));
}
while (parser.hasNext()) {
int event = parser.next();
if (event == XMLStreamConstants.START_ELEMENT) {
parseUnknown(false); /* no more warning for inner elements */
} else if (event == XMLStreamConstants.END_ELEMENT) {
return;
}
}
}
private Collection<Source> parseDoc() throws XMLStreamException {
List<Source> result = new ArrayList<>();
while (parser.hasNext()) {
int event = parser.next();
if (event == XMLStreamConstants.START_ELEMENT) {
if (parser.getLocalName().equals("tag2link")) {
result.addAll(parseRoot());
} else {
parseUnknown();
}
} else if (event == XMLStreamConstants.END_ELEMENT) {
break;
}
}
return result;
}
private Collection<Source> parseRoot() throws XMLStreamException {
List<Source> result = new ArrayList<>();
while (parser.hasNext()) {
int event = parser.next();
if (event == XMLStreamConstants.START_ELEMENT) {
if (parser.getLocalName().equals("src")) {
result.add(parseSource());
} else {
parseUnknown();
}
} else if (event == XMLStreamConstants.END_ELEMENT) {
break;
}
}
return result;
}
private Source parseSource() throws XMLStreamException {
Source source = new Source(parser.getAttributeValue(null, "name"));
while (parser.hasNext()) {
int event = parser.next();
if (event == XMLStreamConstants.START_ELEMENT) {
if (parser.getLocalName().equals("rule")) {
source.rules.add(parseRule());
} else {
parseUnknown();
}
} else if (event == XMLStreamConstants.END_ELEMENT) {
break;
}
}
return source;
}
private Rule parseRule() throws XMLStreamException {
Rule rule = new Rule();
while (parser.hasNext()) {
int event = parser.next();
if (event == XMLStreamConstants.START_ELEMENT) {
if (parser.getLocalName().equals("condition")) {
rule.conditions.add(parseCondition());
} else if (parser.getLocalName().equals("link")) {
rule.links.add(parseLink());
} else {
parseUnknown();
}
} else if (event == XMLStreamConstants.END_ELEMENT) {
break;
}
}
return rule;
}
private Condition parseCondition() throws XMLStreamException {
Condition c = new Condition();
c.keyPattern = Pattern.compile(parser.getAttributeValue(null, "k"));
String v = parser.getAttributeValue(null, "v");
if (v != null) {
c.valPattern = Pattern.compile(v);
}
c.id = parser.getAttributeValue(null, "id");
jumpToEnd();
return c;
}
private Link parseLink() throws XMLStreamException {
Link link = null;
String name = parser.getAttributeValue(null, "name");
String href = parser.getAttributeValue(null, "href");
if ("POST".equals(parser.getAttributeValue(null, "method"))) {
Map<String, String> headers = null;
Map<String, String> params = null;
while (parser.hasNext()) {
int event = parser.next();
if (event == XMLStreamConstants.START_ELEMENT) {
if (parser.getLocalName().equals("header")) {
if (headers == null) {
headers = new HashMap<>();
}
headers.put(parser.getAttributeValue(null, "name"), parser.getAttributeValue(null, "value"));
} else if (parser.getLocalName().equals("param")) {
if (params == null) {
params = new HashMap<>();
}
params.put(parser.getAttributeValue(null, "name"), parser.getAttributeValue(null, "value"));
} else {
parseUnknown();
}
} else if (event == XMLStreamConstants.END_ELEMENT) {
if (parser.getLocalName().equals("link")) {
break;
}
}
}
link = new LinkPost(tr(name), href, headers, params);
} else {
link = new Link(tr(name), href);
jumpToEnd();
}
return link;
}
}