query first page of connection results only once

git-svn-id: https://public-transport-enabler.googlecode.com/svn/trunk@52 0924bc21-9374-b0fa-ee44-9ff1593b38f0
This commit is contained in:
andreas.schildbach 2010-08-08 12:14:04 +00:00
parent 3a9ea3f93f
commit 515dbf7b13
9 changed files with 132 additions and 118 deletions

View file

@ -158,19 +158,19 @@ public final class BahnProvider implements NetworkProvider
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern
.compile("(?:(zu dicht beieinander|mehrfach vorhanden oder identisch)|(leider konnte zu Ihrer Anfrage keine Verbindung gefunden werden))");
public CheckConnectionsQueryResult checkConnectionsQuery(final String from, final String via, final String to, final Date date, final boolean dep)
public QueryConnectionsResult queryConnections(final String from, final String via, final String to, final Date date, final boolean dep)
throws IOException
{
final String queryUri = connectionsQueryUri(from, via, to, date, dep);
final CharSequence page = ParserUtils.scrape(queryUri);
final String uri = connectionsQueryUri(from, via, to, date, dep);
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
if (mError.find())
{
if (mError.group(1) != null)
return CheckConnectionsQueryResult.TOO_CLOSE;
return QueryConnectionsResult.TOO_CLOSE;
if (mError.group(2) != null)
return CheckConnectionsQueryResult.NO_CONNECTIONS;
return QueryConnectionsResult.NO_CONNECTIONS;
}
List<String> fromAddresses = null;
@ -203,9 +203,16 @@ public final class BahnProvider implements NetworkProvider
}
if (fromAddresses != null || viaAddresses != null || toAddresses != null)
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.AMBIGUOUS, queryUri, fromAddresses, viaAddresses, toAddresses);
return new QueryConnectionsResult(QueryConnectionsResult.Status.AMBIGUOUS, fromAddresses, viaAddresses, toAddresses);
else
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.OK, queryUri, null, null, null);
return queryConnections(uri, page);
}
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
return queryConnections(uri, page);
}
private static final Pattern P_CONNECTIONS_HEAD = Pattern.compile(".*" //
@ -221,10 +228,8 @@ public final class BahnProvider implements NetworkProvider
+ "<td class=\"overview iphonepfeil\">(.*?)<br />.*?" // line
, Pattern.DOTALL);
public QueryConnectionsResult queryConnections(final String uri) throws IOException
private QueryConnectionsResult queryConnections(final String uri, final CharSequence page) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mHead = P_CONNECTIONS_HEAD.matcher(page);
if (mHead.matches())
{
@ -270,7 +275,7 @@ public final class BahnProvider implements NetworkProvider
}
}
return new QueryConnectionsResult(from, to, currentDate, linkEarlier, linkLater, connections);
return new QueryConnectionsResult(uri, from, to, currentDate, linkEarlier, linkLater, connections);
}
else
{

View file

@ -1,50 +0,0 @@
/*
* Copyright 2010 the original author or authors.
*
* 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 de.schildbach.pte;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class CheckConnectionsQueryResult
{
public enum Status
{
OK, AMBIGUOUS, TOO_CLOSE, NO_CONNECTIONS;
}
public static final CheckConnectionsQueryResult TOO_CLOSE = new CheckConnectionsQueryResult(Status.TOO_CLOSE, null, null, null, null);
public static final CheckConnectionsQueryResult NO_CONNECTIONS = new CheckConnectionsQueryResult(Status.NO_CONNECTIONS, null, null, null, null);
public final Status status;
public final String queryUri;
public final List<String> ambiguousFromAddresses;
public final List<String> ambiguousViaAddresses;
public final List<String> ambiguousToAddresses;
public CheckConnectionsQueryResult(final Status status, final String queryUri, final List<String> ambiguousFromAddresses,
final List<String> ambiguousViaAddresses, final List<String> ambiguousToAddresses)
{
this.status = status;
this.queryUri = queryUri;
this.ambiguousFromAddresses = ambiguousFromAddresses;
this.ambiguousViaAddresses = ambiguousViaAddresses;
this.ambiguousToAddresses = ambiguousToAddresses;
}
}

View file

@ -17,13 +17,14 @@
package de.schildbach.pte;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class Connection
public final class Connection implements Serializable
{
final public String id;
final public String link;
@ -83,7 +84,7 @@ public final class Connection
return id.hashCode();
}
public static interface Part
public static interface Part extends Serializable
{
}

View file

@ -174,24 +174,24 @@ public class MvvProvider implements NetworkProvider
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern.compile("(?:(xxxzudichtxxx)|(konnte keine Verbindung gefunden werden))",
Pattern.CASE_INSENSITIVE);
public CheckConnectionsQueryResult checkConnectionsQuery(final String from, final String via, final String to, final Date date, final boolean dep)
public QueryConnectionsResult queryConnections(final String from, final String via, final String to, final Date date, final boolean dep)
throws IOException
{
final String queryUri = connectionsQueryUri(from, via, to, date, dep);
CharSequence page = ParserUtils.scrape(queryUri);
final String uri = connectionsQueryUri(from, via, to, date, dep);
CharSequence page = ParserUtils.scrape(uri);
while (page.length() == 0)
{
System.out.println("Got empty page, retrying...");
page = ParserUtils.scrape(queryUri);
page = ParserUtils.scrape(uri);
}
final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
if (mError.find())
{
if (mError.group(1) != null)
return CheckConnectionsQueryResult.TOO_CLOSE;
return QueryConnectionsResult.TOO_CLOSE;
if (mError.group(2) != null)
return CheckConnectionsQueryResult.NO_CONNECTIONS;
return QueryConnectionsResult.NO_CONNECTIONS;
}
List<String> fromAddresses = null;
@ -224,9 +224,21 @@ public class MvvProvider implements NetworkProvider
}
if (fromAddresses != null || viaAddresses != null || toAddresses != null)
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.AMBIGUOUS, queryUri, fromAddresses, viaAddresses, toAddresses);
return new QueryConnectionsResult(QueryConnectionsResult.Status.AMBIGUOUS, fromAddresses, viaAddresses, toAddresses);
else
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.OK, queryUri, null, null, null);
return queryConnections(uri, page);
}
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
CharSequence page = ParserUtils.scrape(uri);
while (page.length() == 0)
{
System.out.println("Got empty page, retrying...");
page = ParserUtils.scrape(uri);
}
return queryConnections(uri, page);
}
private static final Pattern P_CONNECTIONS_HEAD = Pattern.compile(".*<b>Von:[\\xa0\\s]+</b>(.+?)<br />[\\xa0\\s]+"
@ -244,15 +256,8 @@ public class MvvProvider implements NetworkProvider
+ "|" + "Fußweg.*?Dauer:[\\xa0\\s]+(\\d+):(\\d+)" //
+ ").*?", Pattern.DOTALL);
public QueryConnectionsResult queryConnections(final String uri) throws IOException
private QueryConnectionsResult queryConnections(final String uri, final CharSequence page) throws IOException
{
CharSequence page = ParserUtils.scrape(uri);
while (page.length() == 0)
{
System.out.println("Got empty page, retrying...");
page = ParserUtils.scrape(uri);
}
final Matcher mHead = P_CONNECTIONS_HEAD.matcher(page);
if (mHead.matches())
{
@ -318,7 +323,7 @@ public class MvvProvider implements NetworkProvider
}
}
return new QueryConnectionsResult(from, to, currentDate, linkEarlier, linkLater, connections);
return new QueryConnectionsResult(uri, from, to, currentDate, linkEarlier, linkLater, connections);
}
else
{

View file

@ -72,7 +72,7 @@ public interface NetworkProvider
StationLocationResult stationLocation(String stationId) throws IOException;
/**
* Check if query is well defined, asking for any ambiguousnesses
* Query connections, asking for any ambiguousnesses
*
* @param from
* location to route from, mandatory
@ -84,21 +84,20 @@ public interface NetworkProvider
* desired date for departing, mandatory
* @param dep
* date is departure date? {@code true} for departure, {@code false} for arrival
* @return result object that can contain alternatives to clear up ambiguousnesses
* @return result object that can contain alternatives to clear up ambiguousnesses, or contains possible connections
* @throws IOException
*/
CheckConnectionsQueryResult checkConnectionsQuery(String from, String via, String to, Date date, boolean dep) throws IOException;
QueryConnectionsResult queryConnections(String from, String via, String to, Date date, boolean dep) throws IOException;
/**
* Execute well-defined connections query
* Query more connections (e.g. earlier or later)
*
* @param queryUri
* uri constructed by {@link NetworkProvider#connectionsQueryUri} and optionally checked with
* {@link NetworkProvider#checkConnectionsQuery}
* @return result object containing possible connections
* @param uri
* uri to query more connections from
* @return result object that contains possible connections
* @throws IOException
*/
QueryConnectionsResult queryConnections(String queryUri) throws IOException;
QueryConnectionsResult queryMoreConnections(String uri) throws IOException;
/**
* Get details about a connection

View file

@ -17,14 +17,30 @@
package de.schildbach.pte;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* @author Andreas Schildbach
*/
public final class QueryConnectionsResult
public final class QueryConnectionsResult implements Serializable
{
public enum Status
{
OK, AMBIGUOUS, TOO_CLOSE, NO_CONNECTIONS;
}
public static final QueryConnectionsResult TOO_CLOSE = new QueryConnectionsResult(Status.TOO_CLOSE, null, null, null);
public static final QueryConnectionsResult NO_CONNECTIONS = new QueryConnectionsResult(Status.NO_CONNECTIONS, null, null, null);
public final Status status;
public final List<String> ambiguousFromAddresses;
public final List<String> ambiguousViaAddresses;
public final List<String> ambiguousToAddresses;
public final String queryUri;
public final String from;
public final String to;
public final Date currentDate;
@ -32,14 +48,37 @@ public final class QueryConnectionsResult
public final String linkLater;
public final List<Connection> connections;
public QueryConnectionsResult(final String from, final String to, final Date currentDate, final String linkEarlier, final String linkLater,
final List<Connection> connections)
public QueryConnectionsResult(final Status status, final List<String> ambiguousFromAddresses, final List<String> ambiguousViaAddresses,
final List<String> ambiguousToAddresses)
{
this.status = status;
this.ambiguousFromAddresses = ambiguousFromAddresses;
this.ambiguousViaAddresses = ambiguousViaAddresses;
this.ambiguousToAddresses = ambiguousToAddresses;
this.queryUri = null;
this.from = null;
this.to = null;
this.currentDate = null;
this.linkEarlier = null;
this.linkLater = null;
this.connections = null;
}
public QueryConnectionsResult(final String queryUri, final String from, final String to, final Date currentDate, final String linkEarlier,
final String linkLater, final List<Connection> connections)
{
this.status = Status.OK;
this.queryUri = queryUri;
this.from = from;
this.to = to;
this.currentDate = currentDate;
this.linkEarlier = linkEarlier;
this.linkLater = linkLater;
this.connections = connections;
this.ambiguousFromAddresses = null;
this.ambiguousViaAddresses = null;
this.ambiguousToAddresses = null;
}
}

View file

@ -153,6 +153,13 @@ public class RmvProvider implements NetworkProvider
return uri.toString();
}
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
return queryConnections(uri, page);
}
private static final Pattern P_PRE_ADDRESS = Pattern.compile("(?:Geben Sie einen (Startort|Zielort) an.*?)?Bitte w&#228;hlen Sie aus der Liste",
Pattern.DOTALL);
private static final Pattern P_ADDRESSES = Pattern.compile(
@ -160,19 +167,19 @@ public class RmvProvider implements NetworkProvider
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern.compile(
"(?:(mehrfach vorhanden oder identisch)|(keine Verbindung gefunden werden))", Pattern.CASE_INSENSITIVE);
public CheckConnectionsQueryResult checkConnectionsQuery(final String from, final String via, final String to, final Date date, final boolean dep)
public QueryConnectionsResult queryConnections(final String from, final String via, final String to, final Date date, final boolean dep)
throws IOException
{
final String queryUri = connectionsQueryUri(from, via, to, date, dep);
final CharSequence page = ParserUtils.scrape(queryUri);
final String uri = connectionsQueryUri(from, via, to, date, dep);
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
if (mError.find())
{
if (mError.group(1) != null)
return CheckConnectionsQueryResult.TOO_CLOSE;
return QueryConnectionsResult.TOO_CLOSE;
if (mError.group(2) != null)
return CheckConnectionsQueryResult.NO_CONNECTIONS;
return QueryConnectionsResult.NO_CONNECTIONS;
}
List<String> fromAddresses = null;
@ -206,9 +213,9 @@ public class RmvProvider implements NetworkProvider
}
if (fromAddresses != null || viaAddresses != null || toAddresses != null)
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.AMBIGUOUS, queryUri, fromAddresses, viaAddresses, toAddresses);
return new QueryConnectionsResult(QueryConnectionsResult.Status.AMBIGUOUS, fromAddresses, viaAddresses, toAddresses);
else
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.OK, queryUri, null, null, null);
return queryConnections(uri, page);
}
private static final Pattern P_CONNECTIONS_HEAD = Pattern.compile(".*" //
@ -222,10 +229,8 @@ public class RmvProvider implements NetworkProvider
+ "(\\d+:\\d+)-(\\d+:\\d+)</a>" //
+ "(?:&nbsp;(.+?))?", Pattern.DOTALL);
public QueryConnectionsResult queryConnections(final String uri) throws IOException
private QueryConnectionsResult queryConnections(final String uri, final CharSequence page) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mHead = P_CONNECTIONS_HEAD.matcher(page);
if (mHead.matches())
{
@ -271,7 +276,7 @@ public class RmvProvider implements NetworkProvider
}
}
return new QueryConnectionsResult(from, to, currentDate, linkEarlier, linkLater, connections);
return new QueryConnectionsResult(uri, from, to, currentDate, linkEarlier, linkLater, connections);
}
else
{

View file

@ -113,13 +113,18 @@ public class SbbProvider implements NetworkProvider
return uri.toString();
}
public CheckConnectionsQueryResult checkConnectionsQuery(final String from, final String via, final String to, final Date date, final boolean dep)
public QueryConnectionsResult queryConnections(final String from, final String via, final String to, final Date date, final boolean dep)
throws IOException
{
throw new UnsupportedOperationException();
}
public QueryConnectionsResult queryConnections(final String queryUri) throws IOException
public QueryConnectionsResult queryMoreConnections(String uri) throws IOException
{
throw new UnsupportedOperationException();
}
private QueryConnectionsResult queryConnections(final String uri, final CharSequence page) throws IOException
{
throw new UnsupportedOperationException();
}

View file

@ -181,19 +181,19 @@ public final class VbbProvider implements NetworkProvider
private static final Pattern P_CHECK_TO = Pattern.compile("Nach:");
private static final Pattern P_CHECK_CONNECTIONS_ERROR = Pattern.compile("(zu dicht beieinander)|(keine Verbindung gefunden)");
public CheckConnectionsQueryResult checkConnectionsQuery(final String from, final String via, final String to, final Date date, final boolean dep)
public QueryConnectionsResult queryConnections(final String from, final String via, final String to, final Date date, final boolean dep)
throws IOException
{
final String queryUri = connectionsQueryUri(from, via, to, date, dep);
final CharSequence page = ParserUtils.scrape(queryUri);
final String uri = connectionsQueryUri(from, via, to, date, dep);
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mError = P_CHECK_CONNECTIONS_ERROR.matcher(page);
if (mError.find())
{
if (mError.group(1) != null)
return CheckConnectionsQueryResult.TOO_CLOSE;
return QueryConnectionsResult.TOO_CLOSE;
if (mError.group(2) != null)
return CheckConnectionsQueryResult.NO_CONNECTIONS;
return QueryConnectionsResult.NO_CONNECTIONS;
}
final Matcher mAddress = P_CHECK_ADDRESS.matcher(page);
@ -208,21 +208,28 @@ public final class VbbProvider implements NetworkProvider
if (addresses.isEmpty())
{
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.OK, queryUri, null, null, null);
return queryConnections(uri, page);
}
else if (P_CHECK_FROM.matcher(page).find())
{
if (P_CHECK_TO.matcher(page).find())
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.AMBIGUOUS, queryUri, null, addresses, null);
return new QueryConnectionsResult(QueryConnectionsResult.Status.AMBIGUOUS, null, addresses, null);
else
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.AMBIGUOUS, queryUri, null, null, addresses);
return new QueryConnectionsResult(QueryConnectionsResult.Status.AMBIGUOUS, null, null, addresses);
}
else
{
return new CheckConnectionsQueryResult(CheckConnectionsQueryResult.Status.AMBIGUOUS, queryUri, addresses, null, null);
return new QueryConnectionsResult(QueryConnectionsResult.Status.AMBIGUOUS, addresses, null, null);
}
}
public QueryConnectionsResult queryMoreConnections(final String uri) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
return queryConnections(uri, page);
}
private static final Pattern P_CONNECTIONS_HEAD = Pattern.compile(
".*Von: <strong>(.*?)</strong>.*?Nach: <strong>(.*?)</strong>.*?Datum: .., (.*?)<br />.*?"
+ "(?:<a href=\"(/Fahrinfo/bin/query\\.bin/dox.{1,80}ScrollDir=2)\">.*?)?"
@ -231,10 +238,8 @@ public final class VbbProvider implements NetworkProvider
private static final Pattern P_CONNECTIONS_FINE = Pattern.compile(".*?<a href=\"(/Fahrinfo/bin/query\\.bin/dox.*?)\">"
+ "(\\d\\d:\\d\\d)-(\\d\\d:\\d\\d)</a>&nbsp;&nbsp;(?:\\d+ Umst\\.|([\\w\\d ]+)).*?", Pattern.DOTALL);
public QueryConnectionsResult queryConnections(final String uri) throws IOException
private QueryConnectionsResult queryConnections(final String uri, final CharSequence page) throws IOException
{
final CharSequence page = ParserUtils.scrape(uri);
final Matcher mHead = P_CONNECTIONS_HEAD.matcher(page);
if (mHead.matches())
{
@ -276,7 +281,7 @@ public final class VbbProvider implements NetworkProvider
}
}
return new QueryConnectionsResult(from, to, currentDate, linkEarlier, linkLater, connections);
return new QueryConnectionsResult(uri, from, to, currentDate, linkEarlier, linkLater, connections);
}
else
{