diff --git a/src/de/schildbach/pte/AbstractHafasProvider.java b/src/de/schildbach/pte/AbstractHafasProvider.java index 8472e51c..95c2d356 100644 --- a/src/de/schildbach/pte/AbstractHafasProvider.java +++ b/src/de/schildbach/pte/AbstractHafasProvider.java @@ -20,7 +20,11 @@ package de.schildbach.pte; import java.io.IOException; import java.io.InputStream; import java.net.SocketTimeoutException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,9 +35,12 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; +import de.schildbach.pte.dto.Connection; +import de.schildbach.pte.dto.GetConnectionDetailsResult; import de.schildbach.pte.dto.Location; import de.schildbach.pte.dto.LocationType; import de.schildbach.pte.dto.NearbyStationsResult; +import de.schildbach.pte.dto.QueryConnectionsResult; import de.schildbach.pte.dto.Station; import de.schildbach.pte.util.Color; import de.schildbach.pte.util.ParserUtils; @@ -46,29 +53,62 @@ public abstract class AbstractHafasProvider implements NetworkProvider { private static final String DEFAULT_ENCODING = "ISO-8859-1"; - private final String autocompleteUri; - private final String prod; + private final String apiUri; + private static final String prod = "hafas"; private final String accessId; - public AbstractHafasProvider(final String autocompleteUri, final String prod, final String accessId) + public AbstractHafasProvider(final String apiUri, final String accessId) { - this.autocompleteUri = autocompleteUri; - this.prod = prod; + this.apiUri = apiUri; this.accessId = accessId; } + private final String wrap(final String request) + { + return "" // + + "" // + + request // + + ""; + } + + private static final Location parseLocation(final XmlPullParser pp) + { + final String type = pp.getName(); + if ("Station".equals(type)) + { + final String name = pp.getAttributeValue(null, "name").trim(); + final int id = Integer.parseInt(pp.getAttributeValue(null, "externalStationNr")); + final int x = Integer.parseInt(pp.getAttributeValue(null, "x")); + final int y = Integer.parseInt(pp.getAttributeValue(null, "y")); + return new Location(LocationType.STATION, id, y, x, name); + } + throw new IllegalStateException("cannot handle: " + type); + } + + private static final Location parsePoi(final XmlPullParser pp) + { + final String type = pp.getName(); + if ("Poi".equals(type)) + { + String name = pp.getAttributeValue(null, "name").trim(); + if (name.equals("unknown")) + name = null; + final int x = Integer.parseInt(pp.getAttributeValue(null, "x")); + final int y = Integer.parseInt(pp.getAttributeValue(null, "y")); + return new Location(LocationType.POI, 0, y, x, name); + } + throw new IllegalStateException("cannot handle: " + type); + } + public List autocompleteStations(final CharSequence constraint) throws IOException { - final String request = "" // - + "" // - + "" // - + "" // - + ""; + final String request = "" // + + ""; InputStream is = null; try { - is = ParserUtils.scrapeInputStream(autocompleteUri, request); + is = ParserUtils.scrapeInputStream(apiUri, wrap(request)); final List results = new ArrayList(); @@ -85,32 +125,25 @@ public abstract class AbstractHafasProvider implements NetworkProvider while (XmlPullUtil.test(pp, "Station")) { - final String name = pp.getAttributeValue(null, "name"); - final int id = Integer.parseInt(pp.getAttributeValue(null, "externalStationNr")); - final int x = Integer.parseInt(pp.getAttributeValue(null, "x")); - final int y = Integer.parseInt(pp.getAttributeValue(null, "y")); - results.add(new Location(LocationType.STATION, id, y, x, name)); + results.add(parseLocation(pp)); - XmlPullUtil.skipTree(pp); + XmlPullUtil.next(pp); } XmlPullUtil.exit(pp); - XmlPullUtil.require(pp, "LocValRes"); - XmlPullUtil.requireAttr(pp, "id", "poi"); - XmlPullUtil.enter(pp); - - while (XmlPullUtil.test(pp, "Poi")) - { - final String name = pp.getAttributeValue(null, "name"); - final int x = Integer.parseInt(pp.getAttributeValue(null, "x")); - final int y = Integer.parseInt(pp.getAttributeValue(null, "y")); - results.add(new Location(LocationType.POI, 0, y, x, name)); - - XmlPullUtil.skipTree(pp); - } - - XmlPullUtil.exit(pp); + // XmlPullUtil.require(pp, "LocValRes"); + // XmlPullUtil.requireAttr(pp, "id", "poi"); + // XmlPullUtil.enter(pp); + // + // while (XmlPullUtil.test(pp, "Poi")) + // { + // results.add(parsePoi(pp)); + // + // XmlPullUtil.next(pp); + // } + // + // XmlPullUtil.exit(pp); return results; } @@ -129,6 +162,371 @@ public abstract class AbstractHafasProvider implements NetworkProvider } } + public QueryConnectionsResult queryConnections(Location from, Location via, Location to, final Date date, final boolean dep, + final String products, final WalkSpeed walkSpeed) throws IOException + { + if (from.type == LocationType.ANY) + { + final List autocompletes = autocompleteStations(from.name); + if (autocompletes.isEmpty()) + return new QueryConnectionsResult(QueryConnectionsResult.Status.NO_CONNECTIONS); // TODO + if (autocompletes.size() > 1) + return new QueryConnectionsResult(autocompletes, null, null); + from = autocompletes.get(0); + } + + if (via != null && via.type == LocationType.ANY) + { + final List autocompletes = autocompleteStations(via.name); + if (autocompletes.isEmpty()) + return new QueryConnectionsResult(QueryConnectionsResult.Status.NO_CONNECTIONS); // TODO + if (autocompletes.size() > 1) + return new QueryConnectionsResult(null, autocompletes, null); + via = autocompletes.get(0); + } + + if (to.type == LocationType.ANY) + { + final List autocompletes = autocompleteStations(to.name); + if (autocompletes.isEmpty()) + return new QueryConnectionsResult(QueryConnectionsResult.Status.NO_CONNECTIONS); // TODO + if (autocompletes.size() > 1) + return new QueryConnectionsResult(null, null, autocompletes); + to = autocompletes.get(0); + } + + final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd"); + final DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm"); + + final String request = "" // + + "" + location(from) + "" // + + (via != null ? "" + location(via) + "" : "") // + + "" + location(to) + "" // + + "" // + + "" // + + ""; + + // System.out.println(request); + // System.out.println(ParserUtils.scrape(apiUri, true, wrap(request), null, false)); + + InputStream is = null; + try + { + is = ParserUtils.scrapeInputStream(apiUri, wrap(request)); + + final XmlPullParserFactory factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null); + final XmlPullParser pp = factory.newPullParser(); + pp.setInput(is, DEFAULT_ENCODING); + + XmlPullUtil.jump(pp, "ConRes"); + XmlPullUtil.enter(pp); + if (pp.getName().equals("Err")) + { + final String code = XmlPullUtil.attr(pp, "code"); + if (code.equals("K9380")) + return QueryConnectionsResult.TOO_CLOSE; + if (code.equals("K9220")) // Nearby to the given address stations could not be found + return QueryConnectionsResult.NO_CONNECTIONS; + throw new IllegalStateException("error " + code + " " + XmlPullUtil.attr(pp, "text")); + } + + XmlPullUtil.require(pp, "ConResCtxt"); + final String sessionId = XmlPullUtil.text(pp); + XmlPullUtil.require(pp, "ConnectionList"); + XmlPullUtil.enter(pp); + + final List connections = new ArrayList(); + + while (XmlPullUtil.test(pp, "Connection")) + { + final String id = XmlPullUtil.attr(pp, "id"); + + XmlPullUtil.enter(pp); + while (pp.getName().equals("RtStateList")) + XmlPullUtil.next(pp); + XmlPullUtil.require(pp, "Overview"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Date"); + final Date currentDate = DATE_FORMAT.parse(XmlPullUtil.text(pp)); + XmlPullUtil.exit(pp); + XmlPullUtil.require(pp, "ConSectionList"); + XmlPullUtil.enter(pp); + + final List parts = new ArrayList(4); + Date firstDepartureTime = null; + Date lastArrivalTime = null; + + while (XmlPullUtil.test(pp, "ConSection")) + { + XmlPullUtil.enter(pp); + + // departure + XmlPullUtil.require(pp, "Departure"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "BasicStop"); + XmlPullUtil.enter(pp); + while (pp.getName().equals("StAttrList")) + XmlPullUtil.next(pp); + Location departure; + if (pp.getName().equals("Station")) + departure = parseLocation(pp); + else if (pp.getName().equals("Poi")) + departure = parsePoi(pp); + else + throw new IllegalStateException("cannot parse: " + pp.getName()); + XmlPullUtil.next(pp); + XmlPullUtil.require(pp, "Dep"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Time"); + final Date departureTime = ParserUtils.joinDateTime(currentDate, TIME_FORMAT.parse(XmlPullUtil.text(pp).substring(3, 8))); + XmlPullUtil.require(pp, "Platform"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Text"); + String departurePos = XmlPullUtil.text(pp).trim(); + if (departurePos.length() == 0) + departurePos = null; + XmlPullUtil.exit(pp); + + XmlPullUtil.exit(pp); + + XmlPullUtil.exit(pp); + XmlPullUtil.exit(pp); + + // journey + String line = null; + String direction = null; + int min = 0; + + final String tag = pp.getName(); + if (tag.equals("Journey")) + { + XmlPullUtil.enter(pp); + while (pp.getName().equals("JHandle")) + XmlPullUtil.next(pp); + XmlPullUtil.require(pp, "JourneyAttributeList"); + XmlPullUtil.enter(pp); + String name = null; + String category = null; + while (XmlPullUtil.test(pp, "JourneyAttribute")) + { + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Attribute"); + final String attrName = XmlPullUtil.attr(pp, "type"); + XmlPullUtil.enter(pp); + final String attrValue = parseAttributeVariant(pp, "NORMAL"); + XmlPullUtil.exit(pp); + XmlPullUtil.exit(pp); + + if ("NAME".equals(attrName)) + name = attrValue; + else if ("CATEGORY".equals(attrName)) + category = attrValue; + else if ("DIRECTION".equals(attrName)) + direction = attrValue; + } + XmlPullUtil.exit(pp); + XmlPullUtil.exit(pp); + + line = _normalizeLine(category, name); + } + else if (tag.equals("Walk") || tag.equals("Transfer")) + { + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Duration"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Time"); + min = parseDuration(XmlPullUtil.text(pp).substring(3, 8)); + XmlPullUtil.exit(pp); + XmlPullUtil.exit(pp); + } + else + { + throw new IllegalStateException("cannot handle: " + pp.getName()); + } + + // arrival + XmlPullUtil.require(pp, "Arrival"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "BasicStop"); + XmlPullUtil.enter(pp); + while (pp.getName().equals("StAttrList")) + XmlPullUtil.next(pp); + Location arrival; + if (pp.getName().equals("Station")) + arrival = parseLocation(pp); + else if (pp.getName().equals("Poi")) + arrival = parsePoi(pp); + else + throw new IllegalStateException("cannot parse: " + pp.getName()); + XmlPullUtil.next(pp); + XmlPullUtil.require(pp, "Arr"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Time"); + final Date arrivalTime = ParserUtils.joinDateTime(currentDate, TIME_FORMAT.parse(XmlPullUtil.text(pp).substring(3, 8))); + XmlPullUtil.require(pp, "Platform"); + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Text"); + String arrivalPos = XmlPullUtil.text(pp).trim(); + if (arrivalPos.length() == 0) + arrivalPos = null; + XmlPullUtil.exit(pp); + + XmlPullUtil.exit(pp); + + XmlPullUtil.exit(pp); + XmlPullUtil.exit(pp); + + XmlPullUtil.exit(pp); + + if (min == 0 || line != null) + { + parts.add(new Connection.Trip(line, lineColors(line), 0, direction, departureTime, departurePos, departure.id, + departure.name, arrivalTime, arrivalPos, arrival.id, arrival.name)); + } + else + { + if (parts.size() > 0 && parts.get(parts.size() - 1) instanceof Connection.Footway) + { + final Connection.Footway lastFootway = (Connection.Footway) parts.remove(parts.size() - 1); + parts.add(new Connection.Footway(lastFootway.min + min, lastFootway.departureId, lastFootway.departure, arrival.id, + arrival.name)); + } + else + { + parts.add(new Connection.Footway(min, departure.id, departure.name, arrival.id, arrival.name)); + } + } + + if (firstDepartureTime == null) + firstDepartureTime = departureTime; + lastArrivalTime = arrivalTime; + } + + XmlPullUtil.exit(pp); + + XmlPullUtil.exit(pp); + + connections.add(new Connection(id, null, firstDepartureTime, lastArrivalTime, null, null, 0, null, 0, null, parts)); + } + + XmlPullUtil.exit(pp); + + return new QueryConnectionsResult(null, from, via, to, null, null, connections); + } + catch (final XmlPullParserException x) + { + throw new RuntimeException(x); + } + catch (final SocketTimeoutException x) + { + throw new RuntimeException(x); + } + catch (final ParseException x) + { + throw new RuntimeException(x); + } + finally + { + if (is != null) + is.close(); + } + } + + private final String parseAttributeVariant(final XmlPullParser pp, final String type) throws XmlPullParserException, IOException + { + String value = null; + + while (XmlPullUtil.test(pp, "AttributeVariant")) + { + if (type.equals(XmlPullUtil.attr(pp, "type"))) + { + XmlPullUtil.enter(pp); + XmlPullUtil.require(pp, "Text"); + value = XmlPullUtil.text(pp).trim(); + XmlPullUtil.exit(pp); + } + else + { + XmlPullUtil.next(pp); + } + } + + return value; + } + + private static final Pattern P_DURATION = Pattern.compile("(\\d+):(\\d{2})"); + + private final int parseDuration(final String str) + { + final Matcher m = P_DURATION.matcher(str); + if (m.matches()) + return Integer.parseInt(m.group(1)) * 60 + Integer.parseInt(m.group(2)); + else + throw new IllegalArgumentException("cannot parse duration: " + str); + } + + private final String location(final Location location) + { + if (location.type == LocationType.STATION && location.id != 0) + return ""; + if (location.type == LocationType.POI && (location.lat != 0 || location.lon != 0)) + return ""; + + throw new IllegalArgumentException("cannot handle: " + location.toDebugString()); + } + + private final String _normalizeLine(final String type, final String name) + { + final String normalizedType = type.split(" ", 2)[0]; + final String normalizedName = normalizeWhitespace(name); + + if ("THALYS".equals(normalizedType)) + return "I" + normalizedName; + if ("IC".equals(normalizedType)) + return "I" + normalizedName; + if ("EN".equals(normalizedType)) + return "I" + normalizedName; + if ("OEC".equals(normalizedType)) + return "I" + normalizedName; + + if ("R".equals(normalizedType)) + return "R" + normalizedName; + if ("RE".equals(normalizedType)) + return "R" + normalizedName; + if ("IR".equals(normalizedType)) + return "R" + normalizedName; + + if ("Tramway".equals(normalizedType)) + return "T" + normalizedName; + + if ("BUS".equals(normalizedType)) + return "B" + normalizedName; + + if ("L".equals(normalizedType)) + return "?" + normalizedName; + if ("NZ".equals(normalizedType)) + return "?" + normalizedName; + + throw new IllegalStateException("cannot normalize type '" + normalizedType + "' (" + type + ") name '" + normalizedName + "'"); + } + + private final static Pattern P_WHITESPACE = Pattern.compile("\\s+"); + + private final String normalizeWhitespace(final String str) + { + return P_WHITESPACE.matcher(str).replaceAll(""); + } + + public QueryConnectionsResult queryMoreConnections(String uri) throws IOException + { + throw new UnsupportedOperationException(); + } + + public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException + { + throw new UnsupportedOperationException(); + } + private final static Pattern P_NEARBY_COARSE = Pattern.compile("(.*?)", Pattern.DOTALL); private final static Pattern P_NEARBY_FINE_COORDS = Pattern .compile("&REQMapRoute0\\.Location0\\.X=(-?\\d+)&REQMapRoute0\\.Location0\\.Y=(-?\\d+)&"); @@ -200,7 +598,7 @@ public abstract class AbstractHafasProvider implements NetworkProvider if (normalizedType != 0) return normalizedType + strippedLine; - throw new IllegalStateException("cannot normalize type " + type + " line " + line); + throw new IllegalStateException("cannot normalize type '" + type + "' line '" + line + "'"); } protected abstract char normalizeType(String type); diff --git a/src/de/schildbach/pte/NasaProvider.java b/src/de/schildbach/pte/NasaProvider.java index cd3ff13f..a9d392ac 100644 --- a/src/de/schildbach/pte/NasaProvider.java +++ b/src/de/schildbach/pte/NasaProvider.java @@ -48,7 +48,7 @@ public class NasaProvider extends AbstractHafasProvider public NasaProvider() { - super(null, null, null); + super(null, null); } public boolean hasCapabilities(final Capability... capabilities) @@ -250,17 +250,20 @@ public class NasaProvider extends AbstractHafasProvider return 0; } + @Override public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep, final String products, final WalkSpeed walkSpeed) throws IOException { throw new UnsupportedOperationException(); } + @Override public QueryConnectionsResult queryMoreConnections(String uri) throws IOException { throw new UnsupportedOperationException(); } + @Override public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException { throw new UnsupportedOperationException(); diff --git a/src/de/schildbach/pte/OebbProvider.java b/src/de/schildbach/pte/OebbProvider.java index 79f49b18..0c65d036 100644 --- a/src/de/schildbach/pte/OebbProvider.java +++ b/src/de/schildbach/pte/OebbProvider.java @@ -50,7 +50,7 @@ public class OebbProvider extends AbstractHafasProvider public OebbProvider() { - super(null, null, null); + super(null, null); } public boolean hasCapabilities(final Capability... capabilities) @@ -233,6 +233,7 @@ public class OebbProvider extends AbstractHafasProvider "]*>\n(.*?)", Pattern.DOTALL); private static final Pattern P_ADDRESSES = Pattern.compile("]*>\\s*([^<\\[]*)(?:\\[[^\\[]*\\])?\\s*", Pattern.DOTALL); + @Override public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep, final String products, final WalkSpeed walkSpeed) throws IOException { @@ -293,6 +294,7 @@ public class OebbProvider extends AbstractHafasProvider return queryConnections(baseUri, page); } + @Override public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException { final CharSequence page = ParserUtils.scrape(uri, false, null, null, true); @@ -483,6 +485,7 @@ public class OebbProvider extends AbstractHafasProvider } } + @Override public GetConnectionDetailsResult getConnectionDetails(final String connectionUri) throws IOException { throw new UnsupportedOperationException(); diff --git a/src/de/schildbach/pte/RmvProvider.java b/src/de/schildbach/pte/RmvProvider.java index 70584256..3c12c59e 100644 --- a/src/de/schildbach/pte/RmvProvider.java +++ b/src/de/schildbach/pte/RmvProvider.java @@ -53,7 +53,7 @@ public class RmvProvider extends AbstractHafasProvider public RmvProvider() { - super(null, null, null); + super(null, null); } public boolean hasCapabilities(final Capability... capabilities) @@ -184,6 +184,7 @@ public class RmvProvider extends AbstractHafasProvider private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern.compile( "(mehrfach vorhanden oder identisch)|(keine Verbindung gefunden werden)|(derzeit nur Auskünfte vom)", Pattern.CASE_INSENSITIVE); + @Override public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep, final String products, final WalkSpeed walkSpeed) throws IOException { @@ -249,6 +250,7 @@ public class RmvProvider extends AbstractHafasProvider + "(?: (.+?))?" // , Pattern.DOTALL); + @Override public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException { final CharSequence page = ParserUtils.scrape(uri); @@ -333,6 +335,7 @@ public class RmvProvider extends AbstractHafasProvider + "- (.*?)" // arrival , Pattern.DOTALL); + @Override public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException { final CharSequence page = ParserUtils.scrape(uri); diff --git a/src/de/schildbach/pte/SbbProvider.java b/src/de/schildbach/pte/SbbProvider.java index c84d5102..850abe5f 100644 --- a/src/de/schildbach/pte/SbbProvider.java +++ b/src/de/schildbach/pte/SbbProvider.java @@ -45,12 +45,13 @@ public class SbbProvider extends AbstractHafasProvider { public static final String NETWORK_ID = "fahrplan.sbb.ch"; private static final String API_BASE = "http://fahrplan.sbb.ch/bin/"; + private static final String API_URI = "http://fahrplan.sbb.ch/bin/extxml.exe"; private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000; - public SbbProvider() + public SbbProvider(final String accessId) { - super("http://fahrplan.sbb.ch/bin/extxml.exe", "iPhone3.1", "MJXZ841ZfsmqqmSymWhBPy5dMNoqoGsHInHbWJQ5PTUZOJ1rLTkn8vVZOZDFfSe"); + super(API_URI, accessId); } public boolean hasCapabilities(final Capability... capabilities) @@ -131,6 +132,7 @@ public class SbbProvider extends AbstractHafasProvider private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern .compile("(mehrfach vorhanden oder identisch)|(keine Verbindung gefunden werden)|(liegt nach dem Ende der Fahrplanperiode|liegt vor Beginn der Fahrplanperiode)"); + @Override public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep, final String products, final WalkSpeed walkSpeed) throws IOException { @@ -185,6 +187,7 @@ public class SbbProvider extends AbstractHafasProvider return queryConnections(uri, page); } + @Override public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException { final CharSequence page = ParserUtils.scrape(uri); @@ -293,6 +296,7 @@ public class SbbProvider extends AbstractHafasProvider + "- ([^<]*) -\n" // destination , Pattern.DOTALL); + @Override public GetConnectionDetailsResult getConnectionDetails(final String uri) throws IOException { final CharSequence page = ParserUtils.scrape(uri); diff --git a/src/de/schildbach/pte/SncbProvider.java b/src/de/schildbach/pte/SncbProvider.java index 3d7b1123..74d51398 100644 --- a/src/de/schildbach/pte/SncbProvider.java +++ b/src/de/schildbach/pte/SncbProvider.java @@ -27,9 +27,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import de.schildbach.pte.dto.Departure; -import de.schildbach.pte.dto.GetConnectionDetailsResult; -import de.schildbach.pte.dto.Location; -import de.schildbach.pte.dto.QueryConnectionsResult; import de.schildbach.pte.dto.QueryDeparturesResult; import de.schildbach.pte.dto.QueryDeparturesResult.Status; import de.schildbach.pte.util.ParserUtils; @@ -43,17 +40,17 @@ public class SncbProvider extends AbstractHafasProvider private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000; - private static final String AUTOCOMPLETE_URI = "http://hari.b-rail.be/Hafas/bin/extxml.exe"; + private static final String API_URI = "http://hari.b-rail.be/Hafas/bin/extxml.exe"; public SncbProvider() { - super(AUTOCOMPLETE_URI, "irail", null); + super(API_URI, null); } public boolean hasCapabilities(final Capability... capabilities) { for (final Capability capability : capabilities) - if (capability == Capability.DEPARTURES) + if (capability == Capability.DEPARTURES || capability == Capability.CONNECTIONS) return true; return false; @@ -67,22 +64,6 @@ public class SncbProvider extends AbstractHafasProvider return String.format(NEARBY_URI, stationId); } - public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep, - final String products, final WalkSpeed walkSpeed) throws IOException - { - throw new UnsupportedOperationException(); - } - - public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException - { - throw new UnsupportedOperationException(); - } - - public GetConnectionDetailsResult getConnectionDetails(final String connectionUri) throws IOException - { - throw new UnsupportedOperationException(); - } - public String departuresQueryUri(final String stationId, final int maxDepartures) { final StringBuilder uri = new StringBuilder(); diff --git a/src/de/schildbach/pte/VgsProvider.java b/src/de/schildbach/pte/VgsProvider.java index d6a7053a..6cd6a3ee 100644 --- a/src/de/schildbach/pte/VgsProvider.java +++ b/src/de/schildbach/pte/VgsProvider.java @@ -48,7 +48,7 @@ public class VgsProvider extends AbstractHafasProvider public VgsProvider() { - super(null, null, null); + super(null, null); } public boolean hasCapabilities(final Capability... capabilities) @@ -247,17 +247,20 @@ public class VgsProvider extends AbstractHafasProvider return 0; } + @Override public QueryConnectionsResult queryConnections(final Location from, final Location via, final Location to, final Date date, final boolean dep, final String products, final WalkSpeed walkSpeed) throws IOException { throw new UnsupportedOperationException(); } + @Override public QueryConnectionsResult queryMoreConnections(String uri) throws IOException { throw new UnsupportedOperationException(); } + @Override public GetConnectionDetailsResult getConnectionDetails(String connectionUri) throws IOException { throw new UnsupportedOperationException(); diff --git a/src/de/schildbach/pte/util/XmlPullUtil.java b/src/de/schildbach/pte/util/XmlPullUtil.java index 9a879047..784c0175 100644 --- a/src/de/schildbach/pte/util/XmlPullUtil.java +++ b/src/de/schildbach/pte/util/XmlPullUtil.java @@ -32,7 +32,8 @@ public final class XmlPullUtil /** * enters current tag - * @throws IOException + * + * @throws IOException */ public static void enter(final XmlPullParser pp) throws XmlPullParserException, IOException { @@ -40,22 +41,34 @@ public final class XmlPullUtil throw new IllegalStateException("expecting start tag to enter"); if (pp.isEmptyElementTag()) throw new IllegalStateException("cannot enter empty tag"); + pp.next(); } - + public static void exit(final XmlPullParser pp) throws XmlPullParserException, IOException { + while (pp.getEventType() != XmlPullParser.END_TAG) + { + if (pp.getEventType() == XmlPullParser.START_TAG) + next(pp); + else if (pp.getEventType() == XmlPullParser.TEXT) + pp.next(); + else + throw new IllegalStateException(); + } + if (pp.getEventType() != XmlPullParser.END_TAG) throw new IllegalStateException("expecting end tag to exit"); + pp.next(); } - + public static boolean test(final XmlPullParser pp, final String tagName) throws XmlPullParserException { return pp.getEventType() == XmlPullParser.START_TAG && pp.getName().equals(tagName); } - - public static void skipTree(final XmlPullParser pp) throws XmlPullParserException, IOException + + public static void next(final XmlPullParser pp) throws XmlPullParserException, IOException { skipSubTree(pp); pp.next(); @@ -82,6 +95,22 @@ public final class XmlPullUtil throw new IllegalStateException("cannot find " + attrName + "=\"" + requiredValue + "\" />"); } + public static String text(final XmlPullParser pp) throws XmlPullParserException, IOException + { + if (pp.getEventType() != XmlPullParser.START_TAG || pp.isEmptyElementTag()) + throw new IllegalStateException("expecting start tag to get text from"); + + enter(pp); + + String text = ""; + if (pp.getEventType() == XmlPullParser.TEXT) + text = pp.getText(); + + exit(pp); + + return text; + } + /** * Return value of attribute with given name and no namespace. */ diff --git a/test/de/schildbach/pte/live/SbbProviderLiveTest.java b/test/de/schildbach/pte/live/SbbProviderLiveTest.java index 0cec0a35..5aec87e7 100644 --- a/test/de/schildbach/pte/live/SbbProviderLiveTest.java +++ b/test/de/schildbach/pte/live/SbbProviderLiveTest.java @@ -36,7 +36,7 @@ import de.schildbach.pte.dto.QueryDeparturesResult; */ public class SbbProviderLiveTest { - private SbbProvider provider = new SbbProvider(); + private SbbProvider provider = new SbbProvider(Secrets.SBB_ACCESS_ID); private static final String ALL_PRODUCTS = "IRSUTBFC"; @Test @@ -74,8 +74,8 @@ public class SbbProviderLiveTest @Test public void shortConnection() throws Exception { - final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.ANY, 0, 0, 0, "Zürich!"), null, new Location( - LocationType.ANY, 0, 0, 0, "Bern"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL); + final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.STATION, 8503000, 0, 0, "Zürich HB"), null, + new Location(LocationType.STATION, 8507785, 0, 0, "Bern, Hauptbahnhof"), new Date(), true, ALL_PRODUCTS, WalkSpeed.NORMAL); System.out.println(result); final QueryConnectionsResult moreResult = provider.queryMoreConnections(result.linkLater); System.out.println(moreResult); diff --git a/test/de/schildbach/pte/live/SncbProviderLiveTest.java b/test/de/schildbach/pte/live/SncbProviderLiveTest.java index 73a907ac..b18cdf53 100644 --- a/test/de/schildbach/pte/live/SncbProviderLiveTest.java +++ b/test/de/schildbach/pte/live/SncbProviderLiveTest.java @@ -16,13 +16,17 @@ */ package de.schildbach.pte.live; +import java.util.Date; import java.util.List; import org.junit.Test; import de.schildbach.pte.SncbProvider; +import de.schildbach.pte.NetworkProvider.WalkSpeed; import de.schildbach.pte.dto.Location; +import de.schildbach.pte.dto.LocationType; import de.schildbach.pte.dto.NearbyStationsResult; +import de.schildbach.pte.dto.QueryConnectionsResult; /** * @author Andreas Schildbach @@ -47,6 +51,24 @@ public class SncbProviderLiveTest System.out.println(); } + @Test + public void shortConnection() throws Exception + { + final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.STATION, 100024, 0, 0, null), null, new Location( + LocationType.STATION, 100066, 0, 0, null), new Date(), true, null, WalkSpeed.FAST); + + System.out.println(result.status + " " + result.connections); + } + + @Test + public void longConnection() throws Exception + { + final QueryConnectionsResult result = provider.queryConnections(new Location(LocationType.STATION, 100024, 0, 0, null), null, new Location( + LocationType.STATION, 103624, 0, 0, null), new Date(), true, null, WalkSpeed.FAST); + + System.out.println(result.status + " " + result.connections); + } + @Test public void nearbyStation() throws Exception {