mirror of
https://gitlab.com/oeffi/public-transport-enabler.git
synced 2025-07-19 16:59:51 +00:00
Migrate all HTTP calls to use OkHttp rather than URLConnection.
This commit is contained in:
parent
4c64746e75
commit
74d552d187
16 changed files with 2135 additions and 2062 deletions
|
@ -2,6 +2,8 @@ apply plugin: 'java'
|
|||
apply plugin: 'eclipse'
|
||||
|
||||
dependencies {
|
||||
compile 'com.squareup.okhttp3:okhttp:3.4.1'
|
||||
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
|
||||
compile 'com.google.guava:guava:18.0'
|
||||
compile 'org.slf4j:slf4j-api:1.7.12'
|
||||
compile 'com.google.code.findbugs:jsr305:3.0.0'
|
||||
|
|
|
@ -83,6 +83,9 @@ import de.schildbach.pte.util.HttpClient;
|
|||
import de.schildbach.pte.util.ParserUtils;
|
||||
import de.schildbach.pte.util.XmlPullUtil;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
|
@ -244,10 +247,10 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
final StringBuilder parameters = stopfinderRequestParameters(constraint, "JSON");
|
||||
final CharSequence page;
|
||||
if (httpPost)
|
||||
page = httpClient.get(uri.toString(), parameters.substring(1), "application/x-www-form-urlencoded",
|
||||
Charsets.UTF_8);
|
||||
page = httpClient.get(HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", Charsets.UTF_8);
|
||||
else
|
||||
page = httpClient.get(uri.append(parameters).toString(), Charsets.UTF_8);
|
||||
page = httpClient.get(HttpUrl.parse(uri.append(parameters).toString()), Charsets.UTF_8);
|
||||
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
|
||||
|
||||
try {
|
||||
|
@ -354,20 +357,14 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
protected SuggestLocationsResult xmlStopfinderRequest(final Location constraint) throws IOException {
|
||||
final StringBuilder uri = new StringBuilder(stopFinderEndpoint);
|
||||
final StringBuilder parameters = stopfinderRequestParameters(constraint, "XML");
|
||||
final AtomicReference<SuggestLocationsResult> result = new AtomicReference<SuggestLocationsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpReferer);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.byteStream(), null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterItdRequest(pp);
|
||||
|
||||
final List<SuggestedLocation> locations = new ArrayList<SuggestedLocation>();
|
||||
|
@ -383,32 +380,33 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
|
||||
XmlPullUtil.skipExit(pp, "itdStopFinderRequest");
|
||||
|
||||
return new SuggestLocationsResult(header, locations);
|
||||
result.set(new SuggestLocationsResult(header, locations));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null, httpReferer);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
protected SuggestLocationsResult mobileStopfinderRequest(final Location constraint) throws IOException {
|
||||
final StringBuilder uri = new StringBuilder(stopFinderEndpoint);
|
||||
final StringBuilder parameters = stopfinderRequestParameters(constraint, "XML");
|
||||
final AtomicReference<SuggestLocationsResult> result = new AtomicReference<SuggestLocationsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpReferer);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.byteStream(), null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterEfa(pp);
|
||||
|
||||
final List<SuggestedLocation> locations = new ArrayList<SuggestedLocation>();
|
||||
|
@ -456,8 +454,8 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
|
||||
XmlPullUtil.skipExit(pp, "p");
|
||||
|
||||
final Location location = new Location(type, type == LocationType.STATION ? id : null, coord, place,
|
||||
name);
|
||||
final Location location = new Location(type, type == LocationType.STATION ? id : null,
|
||||
coord, place, name);
|
||||
final SuggestedLocation locationAndQuality = new SuggestedLocation(location, quality);
|
||||
locations.add(locationAndQuality);
|
||||
}
|
||||
|
@ -467,14 +465,21 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.next(pp);
|
||||
}
|
||||
|
||||
return new SuggestLocationsResult(header, locations);
|
||||
result.set(new SuggestLocationsResult(header, locations));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null, httpReferer);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private StringBuilder xmlCoordRequestParameters(final EnumSet<LocationType> types, final int lat, final int lon,
|
||||
final int maxDistance, final int maxLocations) {
|
||||
|
@ -507,20 +512,14 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
final int maxDistance, final int maxStations) throws IOException {
|
||||
final StringBuilder uri = new StringBuilder(coordEndpoint);
|
||||
final StringBuilder parameters = xmlCoordRequestParameters(types, lat, lon, maxDistance, maxStations);
|
||||
final AtomicReference<NearbyLocationsResult> result = new AtomicReference<NearbyLocationsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpReferer);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.byteStream(), null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterItdRequest(pp);
|
||||
|
||||
XmlPullUtil.enter(pp, "itdCoordInfoRequest");
|
||||
|
@ -566,33 +565,34 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.skipExit(pp, "coordInfoItemList");
|
||||
}
|
||||
|
||||
return new NearbyLocationsResult(header, locations);
|
||||
result.set(new NearbyLocationsResult(header, locations));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null, httpReferer);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
protected NearbyLocationsResult mobileCoordRequest(final EnumSet<LocationType> types, final int lat, final int lon,
|
||||
final int maxDistance, final int maxStations) throws IOException {
|
||||
final StringBuilder uri = new StringBuilder(coordEndpoint);
|
||||
final StringBuilder parameters = xmlCoordRequestParameters(types, lat, lon, maxDistance, maxStations);
|
||||
final AtomicReference<NearbyLocationsResult> result = new AtomicReference<NearbyLocationsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpReferer);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.byteStream(), null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterEfa(pp);
|
||||
|
||||
XmlPullUtil.enter(pp, "ci");
|
||||
|
@ -643,14 +643,21 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
|
||||
XmlPullUtil.skipExit(pp, "ci");
|
||||
|
||||
return new NearbyLocationsResult(header, stations);
|
||||
result.set(new NearbyLocationsResult(header, stations));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null, httpReferer);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuggestLocationsResult suggestLocations(final CharSequence constraint) throws IOException {
|
||||
|
@ -856,20 +863,14 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
parameters.append("&mergeDep=1");
|
||||
parameters.append("&useAllStops=1");
|
||||
parameters.append("&mode=direct");
|
||||
final AtomicReference<NearbyLocationsResult> result = new AtomicReference<NearbyLocationsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpReferer);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.byteStream(), null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterItdRequest(pp);
|
||||
|
||||
XmlPullUtil.enter(pp, "itdDepartureMonitorRequest");
|
||||
|
@ -891,23 +892,32 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
}
|
||||
});
|
||||
|
||||
if ("notidentified".equals(nameState))
|
||||
return new NearbyLocationsResult(header, NearbyLocationsResult.Status.INVALID_ID);
|
||||
if ("notidentified".equals(nameState)) {
|
||||
result.set(new NearbyLocationsResult(header, NearbyLocationsResult.Status.INVALID_ID));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ownStation.get() != null && !stations.contains(ownStation))
|
||||
stations.add(ownStation.get());
|
||||
|
||||
if (maxLocations == 0 || maxLocations >= stations.size())
|
||||
return new NearbyLocationsResult(header, stations);
|
||||
result.set(new NearbyLocationsResult(header, stations));
|
||||
else
|
||||
return new NearbyLocationsResult(header, stations.subList(0, maxLocations));
|
||||
result.set(new NearbyLocationsResult(header, stations.subList(0, maxLocations)));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null, httpReferer);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private static final Pattern P_LINE_RE = Pattern.compile("RE ?\\d+");
|
||||
private static final Pattern P_LINE_RB = Pattern.compile("RB ?\\d+");
|
||||
|
@ -1442,23 +1452,17 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
final int maxDepartures, final boolean equivs) throws IOException {
|
||||
final StringBuilder uri = new StringBuilder(departureMonitorEndpoint);
|
||||
final StringBuilder parameters = xsltDepartureMonitorRequestParameters(stationId, time, maxDepartures, equivs);
|
||||
final AtomicReference<QueryDeparturesResult> result = new AtomicReference<QueryDeparturesResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpReferer);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.byteStream(), null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterItdRequest(pp);
|
||||
|
||||
final QueryDeparturesResult result = new QueryDeparturesResult(header);
|
||||
final QueryDeparturesResult r = new QueryDeparturesResult(header);
|
||||
|
||||
XmlPullUtil.enter(pp, "itdDepartureMonitorRequest");
|
||||
|
||||
|
@ -1468,14 +1472,16 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
@Override
|
||||
public void location(final String nameState, final Location location, final int matchQuality) {
|
||||
if (location.type == LocationType.STATION)
|
||||
if (findStationDepartures(result.stationDepartures, location.id) == null)
|
||||
result.stationDepartures.add(new StationDepartures(location, new LinkedList<Departure>(),
|
||||
if (findStationDepartures(r.stationDepartures, location.id) == null)
|
||||
r.stationDepartures.add(new StationDepartures(location, new LinkedList<Departure>(),
|
||||
new LinkedList<LineDestination>()));
|
||||
}
|
||||
});
|
||||
|
||||
if ("notidentified".equals(nameState) || "list".equals(nameState))
|
||||
return new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION);
|
||||
if ("notidentified".equals(nameState) || "list".equals(nameState)) {
|
||||
result.set(new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION));
|
||||
return;
|
||||
}
|
||||
|
||||
XmlPullUtil.optSkip(pp, "itdDateTime");
|
||||
|
||||
|
@ -1495,13 +1501,15 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.enter(pp, "itdServingLines");
|
||||
while (XmlPullUtil.test(pp, "itdServingLine")) {
|
||||
final String assignedStopId = XmlPullUtil.optAttr(pp, "assignedStopID", null);
|
||||
final String destinationName = normalizeLocationName(XmlPullUtil.optAttr(pp, "direction", null));
|
||||
final String destinationName = normalizeLocationName(
|
||||
XmlPullUtil.optAttr(pp, "direction", null));
|
||||
final String destinationIdStr = XmlPullUtil.optAttr(pp, "destID", null);
|
||||
final String destinationId = !"-1".equals(destinationIdStr) ? destinationIdStr : null;
|
||||
final Location destination;
|
||||
if (destinationId != null || destinationName != null)
|
||||
destination = new Location(destinationId != null ? LocationType.STATION : LocationType.ANY,
|
||||
destinationId, null, destinationName);
|
||||
destination = new Location(
|
||||
destinationId != null ? LocationType.STATION : LocationType.ANY, destinationId,
|
||||
null, destinationName);
|
||||
else
|
||||
destination = null;
|
||||
|
||||
|
@ -1509,9 +1517,9 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
|
||||
StationDepartures assignedStationDepartures;
|
||||
if (assignedStopId == null)
|
||||
assignedStationDepartures = result.stationDepartures.get(0);
|
||||
assignedStationDepartures = r.stationDepartures.get(0);
|
||||
else
|
||||
assignedStationDepartures = findStationDepartures(result.stationDepartures, assignedStopId);
|
||||
assignedStationDepartures = findStationDepartures(r.stationDepartures, assignedStopId);
|
||||
|
||||
if (assignedStationDepartures == null)
|
||||
assignedStationDepartures = new StationDepartures(
|
||||
|
@ -1534,7 +1542,7 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
while (XmlPullUtil.test(pp, "itdDeparture")) {
|
||||
final String assignedStopId = XmlPullUtil.attr(pp, "stopID");
|
||||
|
||||
StationDepartures assignedStationDepartures = findStationDepartures(result.stationDepartures,
|
||||
StationDepartures assignedStationDepartures = findStationDepartures(r.stationDepartures,
|
||||
assignedStopId);
|
||||
if (assignedStationDepartures == null) {
|
||||
final Point coord = processCoordAttr(pp);
|
||||
|
@ -1542,8 +1550,8 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
// final String name = normalizeLocationName(XmlPullUtil.attr(pp, "nameWO"));
|
||||
|
||||
assignedStationDepartures = new StationDepartures(
|
||||
new Location(LocationType.STATION, assignedStopId, coord), new LinkedList<Departure>(),
|
||||
new LinkedList<LineDestination>());
|
||||
new Location(LocationType.STATION, assignedStopId, coord),
|
||||
new LinkedList<Departure>(), new LinkedList<LineDestination>());
|
||||
}
|
||||
|
||||
final Position position = parsePosition(XmlPullUtil.optAttr(pp, "platformName", null));
|
||||
|
@ -1563,13 +1571,15 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
|
||||
XmlPullUtil.require(pp, "itdServingLine");
|
||||
final boolean isRealtime = XmlPullUtil.attr(pp, "realtime").equals("1");
|
||||
final String destinationName = normalizeLocationName(XmlPullUtil.optAttr(pp, "direction", null));
|
||||
final String destinationName = normalizeLocationName(
|
||||
XmlPullUtil.optAttr(pp, "direction", null));
|
||||
final String destinationIdStr = XmlPullUtil.optAttr(pp, "destID", null);
|
||||
final String destinationId = !"-1".equals(destinationIdStr) ? destinationIdStr : null;
|
||||
final Location destination;
|
||||
if (destinationId != null || destinationName != null)
|
||||
destination = new Location(destinationId != null ? LocationType.STATION : LocationType.ANY,
|
||||
destinationId, null, destinationName);
|
||||
destination = new Location(
|
||||
destinationId != null ? LocationType.STATION : LocationType.ANY, destinationId,
|
||||
null, destinationName);
|
||||
else
|
||||
destination = null;
|
||||
final Line line = processItdServingLine(pp);
|
||||
|
@ -1580,8 +1590,8 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.skipExit(pp, "itdDeparture");
|
||||
|
||||
final Departure departure = new Departure(plannedDepartureTime.getTime(),
|
||||
predictedDepartureTime.isSet(Calendar.HOUR_OF_DAY) ? predictedDepartureTime.getTime()
|
||||
: null,
|
||||
predictedDepartureTime.isSet(Calendar.HOUR_OF_DAY)
|
||||
? predictedDepartureTime.getTime() : null,
|
||||
line, position, destination, null, null);
|
||||
assignedStationDepartures.departures.add(departure);
|
||||
}
|
||||
|
@ -1591,35 +1601,36 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.next(pp);
|
||||
}
|
||||
|
||||
return result;
|
||||
result.set(r);
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null, httpReferer);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
protected QueryDeparturesResult queryDeparturesMobile(final String stationId, final @Nullable Date time,
|
||||
final int maxDepartures, final boolean equivs) throws IOException {
|
||||
final StringBuilder uri = new StringBuilder(departureMonitorEndpoint);
|
||||
final StringBuilder parameters = xsltDepartureMonitorRequestParameters(stationId, time, maxDepartures, equivs);
|
||||
final AtomicReference<QueryDeparturesResult> result = new AtomicReference<QueryDeparturesResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpReferer);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.byteStream(), null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterEfa(pp);
|
||||
final QueryDeparturesResult result = new QueryDeparturesResult(header);
|
||||
final QueryDeparturesResult r = new QueryDeparturesResult(header);
|
||||
|
||||
XmlPullUtil.require(pp, "dps");
|
||||
if (!pp.isEmptyElementTag()) {
|
||||
|
@ -1652,15 +1663,17 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
|
||||
// TODO messages
|
||||
|
||||
StationDepartures stationDepartures = findStationDepartures(result.stationDepartures, assignedId);
|
||||
StationDepartures stationDepartures = findStationDepartures(r.stationDepartures,
|
||||
assignedId);
|
||||
if (stationDepartures == null) {
|
||||
stationDepartures = new StationDepartures(new Location(LocationType.STATION, assignedId),
|
||||
stationDepartures = new StationDepartures(
|
||||
new Location(LocationType.STATION, assignedId),
|
||||
new ArrayList<Departure>(maxDepartures), null);
|
||||
result.stationDepartures.add(stationDepartures);
|
||||
r.stationDepartures.add(stationDepartures);
|
||||
}
|
||||
|
||||
stationDepartures.departures.add(new Departure(
|
||||
plannedDepartureTime.getTime(), predictedDepartureTime.isSet(Calendar.HOUR_OF_DAY)
|
||||
stationDepartures.departures.add(new Departure(plannedDepartureTime.getTime(),
|
||||
predictedDepartureTime.isSet(Calendar.HOUR_OF_DAY)
|
||||
? predictedDepartureTime.getTime() : null,
|
||||
lineDestination.line, position, lineDestination.destination, null, null));
|
||||
|
||||
|
@ -1669,17 +1682,24 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
|
||||
XmlPullUtil.skipExit(pp, "dps");
|
||||
|
||||
return result;
|
||||
result.set(r);
|
||||
} else {
|
||||
return new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION);
|
||||
result.set(new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION));
|
||||
}
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpReferer);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null, httpReferer);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private static final Pattern P_MOBILE_M_SYMBOL = Pattern.compile("([^\\s]*)\\s+([^\\s]*)");
|
||||
|
||||
|
@ -2032,28 +2052,30 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
final StringBuilder uri = new StringBuilder(tripEndpoint);
|
||||
final String parameters = xsltTripRequestParameters(from, via, to, date, dep, products, optimize, walkSpeed,
|
||||
accessibility, options);
|
||||
final AtomicReference<QueryTripsResult> result = new AtomicReference<QueryTripsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpRefererTrip);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpRefererTrip);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
return queryTrips(uri.toString(), is);
|
||||
result.set(queryTrips(uri.toString(), body.byteStream()));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
} catch (final RuntimeException x) {
|
||||
throw new RuntimeException("uncategorized problem while processing " + uri, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpRefererTrip);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null,
|
||||
httpRefererTrip);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
protected QueryTripsResult queryTripsMobile(final Location from, final @Nullable Location via, final Location to,
|
||||
final Date date, final boolean dep, final @Nullable Collection<Product> products,
|
||||
|
@ -2062,28 +2084,30 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
final StringBuilder uri = new StringBuilder(tripEndpoint);
|
||||
final String parameters = xsltTripRequestParameters(from, via, to, date, dep, products, optimize, walkSpeed,
|
||||
accessibility, options);
|
||||
final AtomicReference<QueryTripsResult> result = new AtomicReference<QueryTripsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
if (httpPost)
|
||||
is = httpClient.getInputStream(uri.toString(), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpRefererTrip);
|
||||
else
|
||||
is = httpClient.getInputStream(uri.append(parameters).toString(), null, httpRefererTrip);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
return queryTripsMobile(uri.toString(), from, via, to, is);
|
||||
result.set(queryTripsMobile(uri.toString(), from, via, to, body.byteStream()));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
} catch (final RuntimeException x) {
|
||||
throw new RuntimeException("uncategorized problem while processing " + uri, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (httpPost)
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), parameters.substring(1),
|
||||
"application/x-www-form-urlencoded", null, httpRefererTrip);
|
||||
else
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.append(parameters).toString()), null,
|
||||
httpRefererTrip);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryTripsResult queryMoreTrips(final QueryTripsContext contextObj, final boolean later) throws IOException {
|
||||
|
@ -2091,24 +2115,25 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
final String commandUri = context.context;
|
||||
final StringBuilder uri = new StringBuilder(commandUri);
|
||||
uri.append("&command=").append(later ? "tripNext" : "tripPrev");
|
||||
final AtomicReference<QueryTripsResult> result = new AtomicReference<QueryTripsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
is = httpClient.getInputStream(uri.toString(), null, httpRefererTrip);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
return queryTrips(uri.toString(), is);
|
||||
result.set(queryTrips(uri.toString(), body.byteStream()));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
} catch (final RuntimeException x) {
|
||||
throw new RuntimeException("uncategorized problem while processing " + uri, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), null, httpRefererTrip);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
protected QueryTripsResult queryMoreTripsMobile(final QueryTripsContext contextObj, final boolean later)
|
||||
throws IOException {
|
||||
|
@ -2116,30 +2141,30 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
final String commandUri = context.context;
|
||||
final StringBuilder uri = new StringBuilder(commandUri);
|
||||
uri.append("&command=").append(later ? "tripNext" : "tripPrev");
|
||||
final AtomicReference<QueryTripsResult> result = new AtomicReference<QueryTripsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
is = httpClient.getInputStream(uri.toString(), null, httpRefererTrip);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
is.mark(512);
|
||||
|
||||
return queryTripsMobile(uri.toString(), null, null, null, is);
|
||||
result.set(queryTripsMobile(uri.toString(), null, null, null, body.byteStream()));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
} catch (final RuntimeException x) {
|
||||
throw new RuntimeException("uncategorized problem while processing " + uri, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()), null, httpRefererTrip);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private QueryTripsResult queryTrips(final String uri, final InputStream is)
|
||||
throws XmlPullParserException, IOException {
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(is, null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterItdRequest(pp);
|
||||
final Object context = header.context;
|
||||
|
||||
|
@ -2659,7 +2684,7 @@ public abstract class AbstractEfaProvider extends AbstractNetworkProvider {
|
|||
private QueryTripsResult queryTripsMobile(final String uri, final Location from, final @Nullable Location via,
|
||||
final Location to, final InputStream is) throws XmlPullParserException, IOException {
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(is, null); // Read encoding from XML declaration
|
||||
final ResultHeader header = enterEfa(pp);
|
||||
|
||||
final Calendar plannedTimeCal = new GregorianCalendar(timeZone);
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.io.DataInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
|
@ -44,8 +43,10 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -89,6 +90,9 @@ import de.schildbach.pte.util.ParserUtils;
|
|||
import de.schildbach.pte.util.StringReplaceReader;
|
||||
import de.schildbach.pte.util.XmlPullUtil;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
|
@ -448,7 +452,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
private static final Pattern P_AJAX_GET_STOPS_ID = Pattern.compile(".*?@L=0*(\\d+)@.*?");
|
||||
|
||||
protected final SuggestLocationsResult jsonGetStops(final String uri) throws IOException {
|
||||
final CharSequence page = httpClient.get(uri, jsonGetStopsEncoding);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri), jsonGetStopsEncoding);
|
||||
|
||||
final Matcher mJson = P_AJAX_GET_STOPS_JSON.matcher(page);
|
||||
if (mJson.matches()) {
|
||||
|
@ -565,15 +569,17 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
|
||||
protected final QueryDeparturesResult xmlStationBoard(final String uri, final String stationId) throws IOException {
|
||||
final String normalizedStationId = normalizeStationId(stationId);
|
||||
final AtomicReference<QueryDeparturesResult> result = new AtomicReference<QueryDeparturesResult>();
|
||||
|
||||
httpClient.getInputStream(new HttpClient.Callback() {
|
||||
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
StringReplaceReader reader = null;
|
||||
String firstChars = null;
|
||||
|
||||
try {
|
||||
// work around unparsable XML
|
||||
final InputStream is = httpClient.getInputStream(uri);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
reader = new StringReplaceReader(new InputStreamReader(is, Charsets.ISO_8859_1), " & ", " & ");
|
||||
reader = new StringReplaceReader(body.charStream(), " & ", " & ");
|
||||
reader.replace("<b>", " ");
|
||||
reader.replace("</b>", " ");
|
||||
reader.replace("<u>", " ");
|
||||
|
@ -586,6 +592,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
reader.replace(" <> ", " ↔ "); // left-right arrow
|
||||
addCustomReplaces(reader);
|
||||
|
||||
try {
|
||||
final XmlPullParserFactory factory = XmlPullParserFactory
|
||||
.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
|
||||
final XmlPullParser pp = factory.newPullParser();
|
||||
|
@ -594,19 +601,22 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
pp.nextTag();
|
||||
|
||||
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
|
||||
final QueryDeparturesResult result = new QueryDeparturesResult(header);
|
||||
final QueryDeparturesResult r = new QueryDeparturesResult(header);
|
||||
|
||||
if (XmlPullUtil.test(pp, "Err")) {
|
||||
final String code = XmlPullUtil.attr(pp, "code");
|
||||
final String text = XmlPullUtil.attr(pp, "text");
|
||||
|
||||
if (code.equals("H730")) // Your input is not valid
|
||||
return new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION);
|
||||
if (code.equals("H730")) {
|
||||
result.set(new QueryDeparturesResult(header, QueryDeparturesResult.Status.INVALID_STATION));
|
||||
return;
|
||||
}
|
||||
if (code.equals("H890")) {
|
||||
result.stationDepartures
|
||||
r.stationDepartures
|
||||
.add(new StationDepartures(new Location(LocationType.STATION, normalizedStationId),
|
||||
Collections.<Departure> emptyList(), null));
|
||||
return result;
|
||||
result.set(r);
|
||||
return;
|
||||
}
|
||||
throw new IllegalArgumentException("unknown error " + code + ", " + text);
|
||||
}
|
||||
|
@ -624,7 +634,8 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
final String evaId = XmlPullUtil.attr(pp, "evaId");
|
||||
if (evaId != null) {
|
||||
if (!evaId.equals(normalizedStationId))
|
||||
throw new IllegalStateException("stationId: " + normalizedStationId + ", evaId: " + evaId);
|
||||
throw new IllegalStateException(
|
||||
"stationId: " + normalizedStationId + ", evaId: " + evaId);
|
||||
|
||||
final String name = XmlPullUtil.attr(pp, "name");
|
||||
if (name != null)
|
||||
|
@ -734,7 +745,8 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
final int[] capacity;
|
||||
if (capacityStr != null && !"0|0".equals(capacityStr)) {
|
||||
final String[] capacityParts = capacityStr.split("\\|");
|
||||
capacity = new int[] { Integer.parseInt(capacityParts[0]), Integer.parseInt(capacityParts[1]) };
|
||||
capacity = new int[] { Integer.parseInt(capacityParts[0]),
|
||||
Integer.parseInt(capacityParts[1]) };
|
||||
} else {
|
||||
capacity = null;
|
||||
}
|
||||
|
@ -758,13 +770,14 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
stationPlaceAndName != null ? stationPlaceAndName[1] : null);
|
||||
} else {
|
||||
final String[] depPlaceAndName = splitStationName(depStation);
|
||||
location = new Location(LocationType.STATION, null, depPlaceAndName[0], depPlaceAndName[1]);
|
||||
location = new Location(LocationType.STATION, null, depPlaceAndName[0],
|
||||
depPlaceAndName[1]);
|
||||
}
|
||||
|
||||
StationDepartures stationDepartures = findStationDepartures(result.stationDepartures, location);
|
||||
StationDepartures stationDepartures = findStationDepartures(r.stationDepartures, location);
|
||||
if (stationDepartures == null) {
|
||||
stationDepartures = new StationDepartures(location, new ArrayList<Departure>(8), null);
|
||||
result.stationDepartures.add(stationDepartures);
|
||||
r.stationDepartures.add(stationDepartures);
|
||||
}
|
||||
|
||||
stationDepartures.departures.add(departure);
|
||||
|
@ -779,17 +792,18 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.requireEndDocument(pp);
|
||||
|
||||
// sort departures
|
||||
for (final StationDepartures stationDepartures : result.stationDepartures)
|
||||
for (final StationDepartures stationDepartures : r.stationDepartures)
|
||||
Collections.sort(stationDepartures.departures, Departure.TIME_COMPARATOR);
|
||||
|
||||
return result;
|
||||
result.set(r);
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (reader != null)
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
}, HttpUrl.parse(uri));
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private StationDepartures findStationDepartures(final List<StationDepartures> stationDepartures,
|
||||
final Location location) {
|
||||
|
@ -813,7 +827,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
false);
|
||||
|
||||
final String uri = checkNotNull(mgateEndpoint);
|
||||
final CharSequence page = httpClient.get(uri, request, "application/json", Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri), request, "application/json", Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -878,7 +892,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
false);
|
||||
|
||||
final String uri = checkNotNull(mgateEndpoint);
|
||||
final CharSequence page = httpClient.get(uri, request, "application/json", Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri), request, "application/json", Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -977,7 +991,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
true);
|
||||
|
||||
final String uri = checkNotNull(mgateEndpoint);
|
||||
final CharSequence page = httpClient.get(uri, request, "application/json", Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri), request, "application/json", Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -1058,7 +1072,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
false);
|
||||
|
||||
final String uri = checkNotNull(mgateEndpoint);
|
||||
final CharSequence page = httpClient.get(uri, request, "application/json", Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri), request, "application/json", Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -1466,20 +1480,16 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
final CharSequence conReq, final Location from, final @Nullable Location via, final Location to)
|
||||
throws IOException {
|
||||
final String request = wrapReqC(conReq, null);
|
||||
|
||||
Reader reader = null;
|
||||
String firstChars = null;
|
||||
|
||||
try {
|
||||
final String endpoint = extXmlEndpoint != null ? extXmlEndpoint : queryEndpoint;
|
||||
final InputStream is = httpClient.getInputStream(endpoint, request, "application/xml", null, null);
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
reader = new InputStreamReader(is, Charsets.ISO_8859_1);
|
||||
|
||||
final AtomicReference<QueryTripsResult> result = new AtomicReference<QueryTripsResult>();
|
||||
httpClient.getInputStream(new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
final XmlPullParserFactory factory = XmlPullParserFactory
|
||||
.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null);
|
||||
final XmlPullParser pp = factory.newPullParser();
|
||||
pp.setInput(reader);
|
||||
pp.setInput(body.charStream());
|
||||
|
||||
XmlPullUtil.require(pp, "ResC");
|
||||
final String product = XmlPullUtil.attr(pp, "prod").split(" ")[0];
|
||||
|
@ -1488,10 +1498,14 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
|
||||
if (XmlPullUtil.test(pp, "Err")) {
|
||||
final String code = XmlPullUtil.attr(pp, "code");
|
||||
if (code.equals("I3")) // Input: date outside of the timetable period
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE);
|
||||
if (code.equals("F1")) // Spool: Error reading the spoolfile
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
|
||||
if (code.equals("I3")) {
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE));
|
||||
return;
|
||||
}
|
||||
if (code.equals("F1")) {
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN));
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("error " + code + " " + XmlPullUtil.attr(pp, "text"));
|
||||
}
|
||||
|
||||
|
@ -1500,35 +1514,96 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
if (XmlPullUtil.test(pp, "Err")) {
|
||||
final String code = XmlPullUtil.attr(pp, "code");
|
||||
log.debug("Hafas error: {}", code);
|
||||
if (code.equals("K9260")) // Unknown departure station
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_FROM);
|
||||
if (code.equals("K9280")) // Unknown intermediate station
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_VIA);
|
||||
if (code.equals("K9300")) // Unknown arrival station
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_TO);
|
||||
if (code.equals("K9360")) // Date outside of the timetable period
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE);
|
||||
if (code.equals("K9380")) // Dep./Arr./Intermed. or equivalent station defined more that once
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE);
|
||||
if (code.equals("K895")) // Departure/Arrival are too near
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE);
|
||||
if (code.equals("K9220")) // Nearby to the given address stations could not be found
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNRESOLVABLE_ADDRESS);
|
||||
if (code.equals("K9240")) // Internal error
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
|
||||
if (code.equals("K890")) // No connections found
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
if (code.equals("K891")) // No route found (try entering an intermediate station)
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
if (code.equals("K899")) // An error occurred
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
|
||||
if (code.equals("K1:890")) // Unsuccessful or incomplete search (direction: forward)
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
if (code.equals("K2:890")) // Unsuccessful or incomplete search (direction: backward)
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
if (code.equals("K9260")) {
|
||||
// Unknown departure station
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_FROM));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K9280")) {
|
||||
// Unknown intermediate station
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_VIA));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K9300")) {
|
||||
// Unknown arrival station
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_TO));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K9360")) {
|
||||
// Date outside of the timetable period
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K9380")) {
|
||||
// Dep./Arr./Intermed. or equivalent station defined more than once
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K895")) {
|
||||
// Departure/Arrival are too near
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K9220")) {
|
||||
// Nearby to the given address stations could not be found
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNRESOLVABLE_ADDRESS));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K9240")) {
|
||||
// Internal error
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K890")) {
|
||||
// No connections found
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K891")) {
|
||||
// No route found (try entering an intermediate station)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K899")) {
|
||||
// An error occurred
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K1:890")) {
|
||||
// Unsuccessful or incomplete search (direction: forward)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
}
|
||||
if (code.equals("K2:890")) {
|
||||
// Unsuccessful or incomplete search (direction: backward)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("error " + code + " " + XmlPullUtil.attr(pp, "text"));
|
||||
}
|
||||
|
||||
// H9380 Dep./Arr./Intermed. or equivalent stations defined more than once
|
||||
// H9360 Error in data field
|
||||
// H9320 The input is incorrect or incomplete
|
||||
// H9300 Unknown arrival station
|
||||
// H9280 Unknown intermediate station
|
||||
// H9260 Unknown departure station
|
||||
// H9250 Part inquiry interrupted
|
||||
// H9240 Unsuccessful search
|
||||
// H9230 An internal error occurred
|
||||
// H9220 Nearby to the given address stations could not be found
|
||||
// H900 Unsuccessful or incomplete search (timetable change)
|
||||
// H892 Inquiry too complex (try entering less intermediate stations)
|
||||
// H891 No route found (try entering an intermediate station)
|
||||
// H890 Unsuccessful search.
|
||||
// H500 Because of too many trains the connection is not complete
|
||||
// H460 One or more stops are passed through multiple times.
|
||||
// H455 Prolonged stop
|
||||
// H410 Display may be incomplete due to change of timetable
|
||||
// H390 Departure/Arrival replaced by an equivalent station
|
||||
// H895 Departure/Arrival are too near
|
||||
// H899 Unsuccessful or incomplete search (timetable change
|
||||
|
||||
final String c = XmlPullUtil.optValueTag(pp, "ConResCtxt", null);
|
||||
final Context context;
|
||||
if (previousContext == null)
|
||||
|
@ -1700,8 +1775,8 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.skipExit(pp, "Dep");
|
||||
}
|
||||
|
||||
intermediateStops.add(new Stop(location, stopArrivalTime, stopArrivalPosition,
|
||||
stopDepartureTime, stopDeparturePosition));
|
||||
intermediateStops.add(new Stop(location, stopArrivalTime,
|
||||
stopArrivalPosition, stopDepartureTime, stopDeparturePosition));
|
||||
}
|
||||
XmlPullUtil.skipExit(pp, "BasicStop");
|
||||
}
|
||||
|
@ -1770,15 +1845,18 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
if (line != null) {
|
||||
final Stop departure = new Stop(sectionDepartureLocation, true, departureTime, null,
|
||||
departurePos, null);
|
||||
final Stop arrival = new Stop(sectionArrivalLocation, false, arrivalTime, null, arrivalPos,
|
||||
null);
|
||||
final Stop arrival = new Stop(sectionArrivalLocation, false, arrivalTime, null,
|
||||
arrivalPos, null);
|
||||
|
||||
legs.add(new Trip.Public(line, destination, departure, arrival, intermediateStops, path, null));
|
||||
legs.add(new Trip.Public(line, destination, departure, arrival, intermediateStops, path,
|
||||
null));
|
||||
} else {
|
||||
if (legs.size() > 0 && legs.get(legs.size() - 1) instanceof Trip.Individual) {
|
||||
final Trip.Individual lastIndividualLeg = (Trip.Individual) legs.remove(legs.size() - 1);
|
||||
final Trip.Individual lastIndividualLeg = (Trip.Individual) legs
|
||||
.remove(legs.size() - 1);
|
||||
legs.add(new Trip.Individual(Trip.Individual.Type.WALK, lastIndividualLeg.departure,
|
||||
lastIndividualLeg.departureTime, sectionArrivalLocation, arrivalTime, null, 0));
|
||||
lastIndividualLeg.departureTime, sectionArrivalLocation, arrivalTime, null,
|
||||
0));
|
||||
} else {
|
||||
legs.add(new Trip.Individual(Trip.Individual.Type.WALK, sectionDepartureLocation,
|
||||
departureTime, sectionArrivalLocation, arrivalTime, null, 0));
|
||||
|
@ -1795,14 +1873,15 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
|
||||
XmlPullUtil.skipExit(pp, "ConnectionList");
|
||||
|
||||
return new QueryTripsResult(header, null, from, via, to, context, trips);
|
||||
result.set(new QueryTripsResult(header, null, from, via, to, context, trips));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (reader != null)
|
||||
reader.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
}, HttpUrl.parse(endpoint), request, "application/xml", null, null);
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private final Location parseLocation(final XmlPullParser pp) throws XmlPullParserException, IOException {
|
||||
final Location location;
|
||||
|
@ -2050,21 +2129,24 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
* Many thanks to Malte Starostik and Robert, who helped a lot with analyzing this API!
|
||||
*/
|
||||
|
||||
LittleEndianDataInputStream is = null;
|
||||
final AtomicReference<QueryTripsResult> result = new AtomicReference<QueryTripsResult>();
|
||||
|
||||
try {
|
||||
final CustomBufferedInputStream bis = new CustomBufferedInputStream(httpClient.getInputStream(uri));
|
||||
final String firstChars = HttpClient.peekFirstChars(bis);
|
||||
httpClient.getInputStream(new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
final CustomBufferedInputStream bis = new CustomBufferedInputStream(
|
||||
new GZIPInputStream(body.byteStream()));
|
||||
|
||||
// initialize input stream
|
||||
is = new LittleEndianDataInputStream(bis);
|
||||
final LittleEndianDataInputStream is = new LittleEndianDataInputStream(bis);
|
||||
is.mark(expectedBufferSize);
|
||||
|
||||
// quick check of status
|
||||
final int version = is.readShortReverse();
|
||||
if (version != 6 && version != 5)
|
||||
throw new IllegalStateException("unknown version: " + version + ", first chars: " + firstChars);
|
||||
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT, Integer.toString(version), 0, null);
|
||||
throw new IllegalStateException("unknown version: " + version + ", first chars: " + bodyPeek);
|
||||
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT, Integer.toString(version), 0,
|
||||
null);
|
||||
|
||||
// quick seek for pointers
|
||||
is.reset();
|
||||
|
@ -2106,8 +2188,10 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
is.skipBytes(30);
|
||||
|
||||
final int numTrips = is.readShortReverse();
|
||||
if (numTrips == 0)
|
||||
return new QueryTripsResult(header, uri, from, via, to, null, new LinkedList<Trip>());
|
||||
if (numTrips == 0) {
|
||||
result.set(new QueryTripsResult(header, uri, from, via, to, null, new LinkedList<Trip>()));
|
||||
return;
|
||||
}
|
||||
|
||||
// read rest of header
|
||||
is.reset();
|
||||
|
@ -2171,12 +2255,12 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
final int stopsOffset = is.readShortReverse();
|
||||
|
||||
// read stations
|
||||
final StationTable stations = new StationTable(is, stationTablePtr, commentTablePtr - stationTablePtr,
|
||||
strings);
|
||||
final StationTable stations = new StationTable(is, stationTablePtr,
|
||||
commentTablePtr - stationTablePtr, strings);
|
||||
|
||||
// read comments
|
||||
final CommentTable comments = new CommentTable(is, commentTablePtr, tripDetailsPtr - commentTablePtr,
|
||||
strings);
|
||||
final CommentTable comments = new CommentTable(is, commentTablePtr,
|
||||
tripDetailsPtr - commentTablePtr, strings);
|
||||
|
||||
final List<Trip> trips = new ArrayList<Trip>(numTrips);
|
||||
|
||||
|
@ -2323,11 +2407,12 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
lineCategory = categoryFromName(lineName);
|
||||
|
||||
is.reset();
|
||||
is.skipBytes(
|
||||
tripDetailsPtr + tripDetailsOffset + tripDetailsLegOffset + iLegs * tripDetailsLegSize);
|
||||
is.skipBytes(tripDetailsPtr + tripDetailsOffset + tripDetailsLegOffset
|
||||
+ iLegs * tripDetailsLegSize);
|
||||
|
||||
if (tripDetailsLegSize != 16)
|
||||
throw new IllegalStateException("unhandled trip details leg size: " + tripDetailsLegSize);
|
||||
throw new IllegalStateException(
|
||||
"unhandled trip details leg size: " + tripDetailsLegSize);
|
||||
|
||||
final long predictedDepartureTime = time(is, resDate, tripDayOffset);
|
||||
final long predictedArrivalTime = time(is, resDate, tripDayOffset);
|
||||
|
@ -2441,8 +2526,8 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
|
||||
final Stop stop = new Stop(stopLocation, plannedStopArrivalDate,
|
||||
validPredictedDate ? predictedStopArrivalDate : null,
|
||||
plannedStopArrivalPosition, predictedStopArrivalPosition, stopArrivalCancelled,
|
||||
plannedStopDepartureDate,
|
||||
plannedStopArrivalPosition, predictedStopArrivalPosition,
|
||||
stopArrivalCancelled, plannedStopDepartureDate,
|
||||
validPredictedDate ? predictedStopDepartureDate : null,
|
||||
plannedStopDeparturePosition, predictedStopDeparturePosition,
|
||||
stopDepartureCancelled);
|
||||
|
@ -2455,7 +2540,8 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
if (type == 1 /* Fussweg */ || type == 3 /* Uebergang */ || type == 4 /* Uebergang */) {
|
||||
final Trip.Individual.Type individualType;
|
||||
if (routingType == null)
|
||||
individualType = type == 1 ? Trip.Individual.Type.WALK : Trip.Individual.Type.TRANSFER;
|
||||
individualType = type == 1 ? Trip.Individual.Type.WALK
|
||||
: Trip.Individual.Type.TRANSFER;
|
||||
else if ("FOOT".equals(routingType))
|
||||
individualType = Trip.Individual.Type.WALK;
|
||||
else if ("BIKE".equals(routingType))
|
||||
|
@ -2530,84 +2616,105 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
final boolean canQueryMore = trips.size() != 1 || trips.get(0).legs.size() != 1
|
||||
|| !(trips.get(0).legs.get(0) instanceof Trip.Individual);
|
||||
|
||||
final QueryTripsResult result = new QueryTripsResult(header, uri, from, via, to,
|
||||
new QueryTripsBinaryContext(requestId, seqNr, ld, bis.getCount(), canQueryMore), trips);
|
||||
|
||||
return result;
|
||||
result.set(new QueryTripsResult(header, uri, from, via, to,
|
||||
new QueryTripsBinaryContext(requestId, seqNr, ld, bis.getCount(), canQueryMore), trips));
|
||||
} else {
|
||||
log.debug("Hafas error: {}", errorCode);
|
||||
if (errorCode == 1)
|
||||
if (errorCode == 1) {
|
||||
throw new SessionExpiredException();
|
||||
else if (errorCode == 2)
|
||||
} else if (errorCode == 2) {
|
||||
// F2: Your search results could not be stored internally.
|
||||
throw new SessionExpiredException();
|
||||
else if (errorCode == 8)
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.AMBIGUOUS);
|
||||
else if (errorCode == 13)
|
||||
// IN13: Our booking system is currently being used by too many users at the same time.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
|
||||
else if (errorCode == 19)
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
|
||||
else if (errorCode == 207)
|
||||
} else if (errorCode == 8) {
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.AMBIGUOUS));
|
||||
return;
|
||||
} else if (errorCode == 13) {
|
||||
// IN13: Our booking system is currently being used by too many users at the same
|
||||
// time.
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN));
|
||||
return;
|
||||
} else if (errorCode == 19) {
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN));
|
||||
return;
|
||||
} else if (errorCode == 207) {
|
||||
// H207: Unfortunately your connection request can currently not be processed.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN);
|
||||
else if (errorCode == 887)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.SERVICE_DOWN));
|
||||
return;
|
||||
} else if (errorCode == 887) {
|
||||
// H887: Your inquiry was too complex. Please try entering less intermediate stations.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
else if (errorCode == 890)
|
||||
// H890: No connections have been found that correspond to your request. It is possible
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
} else if (errorCode == 890) {
|
||||
// H890: No connections have been found that correspond to your request. It is
|
||||
// possible
|
||||
// that the requested service does not operate from or to the places you stated on the
|
||||
// requested date of travel.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
else if (errorCode == 891)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
} else if (errorCode == 891) {
|
||||
// H891: Unfortunately there was no route found. Missing timetable data could be the
|
||||
// reason.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
else if (errorCode == 892)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
} else if (errorCode == 892) {
|
||||
// H892: Your inquiry was too complex. Please try entering less intermediate stations.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
else if (errorCode == 899)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
} else if (errorCode == 899) {
|
||||
// H899: there was an unsuccessful or incomplete search due to a timetable change.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
else if (errorCode == 900)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
} else if (errorCode == 900) {
|
||||
// Unsuccessful or incomplete search (timetable change)
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
else if (errorCode == 9220)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
} else if (errorCode == 9220) {
|
||||
// H9220: Nearby to the given address stations could not be found.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNRESOLVABLE_ADDRESS);
|
||||
else if (errorCode == 9240)
|
||||
// H9240: Unfortunately there was no route found. Perhaps your start or destination is not
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNRESOLVABLE_ADDRESS));
|
||||
return;
|
||||
} else if (errorCode == 9240) {
|
||||
// H9240: Unfortunately there was no route found. Perhaps your start or destination is
|
||||
// not
|
||||
// served at all or with the selected means of transport on the required date/time.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS);
|
||||
else if (errorCode == 9260)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.NO_TRIPS));
|
||||
return;
|
||||
} else if (errorCode == 9260) {
|
||||
// H9260: Unknown departure station
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_FROM);
|
||||
else if (errorCode == 9280)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_FROM));
|
||||
return;
|
||||
} else if (errorCode == 9280) {
|
||||
// H9280: Unknown intermediate station
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_VIA);
|
||||
else if (errorCode == 9300)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_VIA));
|
||||
return;
|
||||
} else if (errorCode == 9300) {
|
||||
// H9300: Unknown arrival station
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_TO);
|
||||
else if (errorCode == 9320)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.UNKNOWN_TO));
|
||||
return;
|
||||
} else if (errorCode == 9320) {
|
||||
// The input is incorrect or incomplete
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE);
|
||||
else if (errorCode == 9360)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE));
|
||||
return;
|
||||
} else if (errorCode == 9360) {
|
||||
// H9360: Unfortunately your connection request can currently not be processed.
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE);
|
||||
else if (errorCode == 9380)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.INVALID_DATE));
|
||||
return;
|
||||
} else if (errorCode == 9380) {
|
||||
// H9380: Dep./Arr./Intermed. or equivalent station defined more than once
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE);
|
||||
else if (errorCode == 895)
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE));
|
||||
return;
|
||||
} else if (errorCode == 895) {
|
||||
// H895: Departure/Arrival are too near
|
||||
return new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE);
|
||||
else
|
||||
result.set(new QueryTripsResult(header, QueryTripsResult.Status.TOO_CLOSE));
|
||||
return;
|
||||
} else {
|
||||
throw new IllegalStateException("error " + errorCode + " on " + uri);
|
||||
}
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}, HttpUrl.parse(uri));
|
||||
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private Location location(final LittleEndianDataInputStream is, final StringTable strings) throws IOException {
|
||||
final String name = strings.read(is);
|
||||
|
@ -2853,7 +2960,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
|
||||
protected final NearbyLocationsResult xmlNearbyStations(final String uri) throws IOException {
|
||||
// scrape page
|
||||
final CharSequence page = httpClient.get(uri);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri));
|
||||
|
||||
final List<Location> stations = new ArrayList<Location>();
|
||||
|
||||
|
@ -2929,7 +3036,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
}
|
||||
|
||||
protected final NearbyLocationsResult jsonNearbyLocations(final String uri) throws IOException {
|
||||
final CharSequence page = httpClient.get(uri, jsonNearbyLocationsEncoding);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri), jsonNearbyLocationsEncoding);
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -3010,7 +3117,7 @@ public abstract class AbstractHafasProvider extends AbstractNetworkProvider {
|
|||
protected final NearbyLocationsResult htmlNearbyStations(final String uri) throws IOException {
|
||||
final List<Location> stations = new ArrayList<Location>();
|
||||
|
||||
final CharSequence page = httpClient.get(uri);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri));
|
||||
String oldZebra = null;
|
||||
|
||||
final Matcher mCoarse = htmlNearbyStationsPattern.matcher(page);
|
||||
|
|
|
@ -66,6 +66,8 @@ import de.schildbach.pte.exception.NotFoundException;
|
|||
import de.schildbach.pte.exception.ParserException;
|
||||
import de.schildbach.pte.util.ParserUtils;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Antonio El Khoury
|
||||
* @author Andreas Schildbach
|
||||
|
@ -641,7 +643,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
|
||||
private String getStopAreaId(final String stopPointId) throws IOException {
|
||||
final String uri = uri() + "stop_points/" + ParserUtils.urlEncode(stopPointId) + "?depth=1";
|
||||
final CharSequence page = httpClient.get(uri);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri));
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -698,7 +700,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
if (maxLocations > 0)
|
||||
queryUri.append("&count=").append(maxLocations);
|
||||
queryUri.append("&depth=3");
|
||||
final CharSequence page = httpClient.get(queryUri.toString());
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(queryUri.toString()));
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -773,7 +775,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
queryUri.append("&duration=86400");
|
||||
queryUri.append("&depth=0");
|
||||
|
||||
final CharSequence page = httpClient.get(queryUri.toString());
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(queryUri.toString()));
|
||||
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
||||
|
@ -821,7 +823,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
throw new ParserException(parseExc);
|
||||
} catch (final NotFoundException fnfExc) {
|
||||
try {
|
||||
final JSONObject head = new JSONObject(fnfExc.scrapeErrorStream().toString());
|
||||
final JSONObject head = new JSONObject(fnfExc.getBodyPeek().toString());
|
||||
final JSONObject error = head.getJSONObject("error");
|
||||
final String id = error.getString("id");
|
||||
|
||||
|
@ -841,7 +843,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
|
||||
final String queryUri = uri() + "places?q=" + ParserUtils.urlEncode(nameCstr)
|
||||
+ "&type[]=stop_area&type[]=address&type[]=poi&type[]=administrative_region" + "&depth=1";
|
||||
final CharSequence page = httpClient.get(queryUri);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(queryUri));
|
||||
|
||||
try {
|
||||
final List<SuggestedLocation> locations = new ArrayList<SuggestedLocation>();
|
||||
|
@ -945,7 +947,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
}
|
||||
}
|
||||
|
||||
final CharSequence page = httpClient.get(queryUri.toString());
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(queryUri.toString()));
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -1013,7 +1015,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
return new QueryTripsResult(resultHeader, QueryTripsResult.Status.NO_TRIPS);
|
||||
} catch (final NotFoundException fnfExc) {
|
||||
try {
|
||||
final JSONObject head = new JSONObject(fnfExc.scrapeErrorStream().toString());
|
||||
final JSONObject head = new JSONObject(fnfExc.getBodyPeek().toString());
|
||||
final JSONObject error = head.getJSONObject("error");
|
||||
final String id = error.getString("id");
|
||||
|
||||
|
@ -1046,7 +1048,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
final Location from = context.from;
|
||||
final Location to = context.to;
|
||||
final String queryUri = later ? context.nextQueryUri : context.prevQueryUri;
|
||||
final CharSequence page = httpClient.get(queryUri);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(queryUri));
|
||||
|
||||
try {
|
||||
if (from.isIdentified() && to.isIdentified()) {
|
||||
|
@ -1076,7 +1078,7 @@ public abstract class AbstractNavitiaProvider extends AbstractNetworkProvider {
|
|||
@Override
|
||||
public Point[] getArea() throws IOException {
|
||||
final String queryUri = uri();
|
||||
final CharSequence page = httpClient.get(queryUri);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(queryUri));
|
||||
|
||||
try {
|
||||
// Get shape string.
|
||||
|
|
|
@ -59,6 +59,8 @@ import de.schildbach.pte.dto.Trip;
|
|||
import de.schildbach.pte.exception.ParserException;
|
||||
import de.schildbach.pte.util.ParserUtils;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Kjell Braden <afflux@pentabarf.de>
|
||||
*/
|
||||
|
@ -197,7 +199,7 @@ public abstract class AbstractTsiProvider extends AbstractNetworkProvider {
|
|||
final StringBuilder uri = new StringBuilder(stopFinderEndpoint);
|
||||
uri.append(parameters);
|
||||
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
try {
|
||||
final List<SuggestedLocation> locations = new ArrayList<SuggestedLocation>();
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -277,7 +279,7 @@ public abstract class AbstractTsiProvider extends AbstractNetworkProvider {
|
|||
final StringBuilder uri = new StringBuilder(stopFinderEndpoint);
|
||||
uri.append(parameters);
|
||||
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
try {
|
||||
final List<Location> stations = new ArrayList<Location>();
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -315,7 +317,7 @@ public abstract class AbstractTsiProvider extends AbstractNetworkProvider {
|
|||
final StringBuilder uri = new StringBuilder(stopFinderEndpoint);
|
||||
uri.append(parameters);
|
||||
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
||||
|
@ -674,7 +676,7 @@ public abstract class AbstractTsiProvider extends AbstractNetworkProvider {
|
|||
|
||||
final StringBuilder uri = new StringBuilder(tripEndpoint);
|
||||
uri.append(parameters);
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package de.schildbach.pte;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.ParsePosition;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -33,6 +32,7 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -63,6 +63,9 @@ import de.schildbach.pte.exception.ParserException;
|
|||
import de.schildbach.pte.util.HttpClient;
|
||||
import de.schildbach.pte.util.XmlPullUtil;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
/**
|
||||
* @author Mats Sjöberg <mats@sjoberg.fi>
|
||||
*/
|
||||
|
@ -137,19 +140,16 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
|
||||
private Location queryStop(final String stationId) throws IOException {
|
||||
final StringBuilder uri = apiUri("stop");
|
||||
|
||||
uri.append("&code=").append(stationId);
|
||||
uri.append(String.format("&dep_limit=1"));
|
||||
final AtomicReference<Location> result = new AtomicReference<Location>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
is = httpClient.getInputStream(uri.toString());
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.charStream());
|
||||
|
||||
XmlPullUtil.enter(pp, "response");
|
||||
XmlPullUtil.enter(pp, "node");
|
||||
|
@ -157,15 +157,16 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
final String id = xmlValueTag(pp, "code");
|
||||
final String name = xmlValueTag(pp, "name_fi");
|
||||
final Point pt = coordStrToPoint(xmlValueTag(pp, "coords"));
|
||||
|
||||
return new Location(LocationType.STATION, id, pt.lat, pt.lon, null, name);
|
||||
result.set(new Location(LocationType.STATION, id, pt.lat, pt.lon, null, name));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()));
|
||||
return result.get();
|
||||
}
|
||||
|
||||
// Determine stations near to given location. At least one of
|
||||
// stationId or lat/lon pair must be present.
|
||||
|
@ -174,7 +175,6 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
public NearbyLocationsResult queryNearbyLocations(EnumSet<LocationType> types, Location location, int maxDistance,
|
||||
int maxStations) throws IOException {
|
||||
final StringBuilder uri = apiUri("stops_area");
|
||||
|
||||
if (!location.hasLocation()) {
|
||||
if (location.type != LocationType.STATION)
|
||||
throw new IllegalArgumentException("cannot handle: " + location.type);
|
||||
|
@ -185,16 +185,14 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
uri.append("¢er_coordinate=").append(locationToCoords(location));
|
||||
uri.append(String.format("&limit=%d", maxStations));
|
||||
uri.append(String.format("&diameter=%d", maxDistance * 2));
|
||||
final AtomicReference<NearbyLocationsResult> result = new AtomicReference<NearbyLocationsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
is = httpClient.getInputStream(uri.toString());
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.charStream());
|
||||
|
||||
final List<Location> stations = new ArrayList<Location>();
|
||||
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
|
||||
|
@ -214,14 +212,16 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
stations.add(new Location(LocationType.STATION, id, pt.lat, pt.lon, place, name));
|
||||
}
|
||||
|
||||
return new NearbyLocationsResult(header, stations);
|
||||
result.set(new NearbyLocationsResult(header, stations));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()));
|
||||
return result.get();
|
||||
}
|
||||
|
||||
private Line newLine(String code, int type, String message) {
|
||||
String label = code.substring(1, 5).trim().replaceAll("^0+", "");
|
||||
|
@ -254,26 +254,23 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
|
||||
// Get departures at a given station, probably live
|
||||
@Override
|
||||
public QueryDeparturesResult queryDepartures(String stationId, @Nullable Date queryDate, int maxDepartures,
|
||||
public QueryDeparturesResult queryDepartures(String stationId, @Nullable Date queryDate, final int maxDepartures,
|
||||
boolean equivs) throws IOException {
|
||||
final StringBuilder uri = apiUri("stop");
|
||||
|
||||
uri.append("&code=").append(stationId);
|
||||
if (queryDate != null) {
|
||||
uri.append("&date=").append(new SimpleDateFormat("yyyyMMdd").format(queryDate));
|
||||
uri.append("&time=").append(new SimpleDateFormat("HHmm").format(queryDate));
|
||||
}
|
||||
uri.append(String.format("&dep_limit=%d", maxDepartures));
|
||||
final AtomicReference<QueryDeparturesResult> result = new AtomicReference<QueryDeparturesResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
is = httpClient.getInputStream(uri.toString());
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.charStream());
|
||||
|
||||
XmlPullUtil.enter(pp, "response");
|
||||
XmlPullUtil.enter(pp, "node");
|
||||
|
@ -293,7 +290,7 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
XmlPullUtil.skipExit(pp, "lines");
|
||||
|
||||
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
|
||||
final QueryDeparturesResult result = new QueryDeparturesResult(header);
|
||||
final QueryDeparturesResult r = new QueryDeparturesResult(header);
|
||||
|
||||
XmlPullUtil.skipUntil(pp, "departures");
|
||||
XmlPullUtil.enter(pp, "departures");
|
||||
|
@ -316,17 +313,17 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
}
|
||||
|
||||
Location station = new Location(LocationType.STATION, id, null, name);
|
||||
result.stationDepartures.add(new StationDepartures(station, departures, null));
|
||||
|
||||
return result;
|
||||
|
||||
r.stationDepartures.add(new StationDepartures(station, departures, null));
|
||||
result.set(r);
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()));
|
||||
return result.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Meant for auto-completion of location names, like in an {@link android.widget.AutoCompleteTextView}
|
||||
|
@ -339,29 +336,23 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
@Override
|
||||
public SuggestLocationsResult suggestLocations(CharSequence constraint) throws IOException {
|
||||
final StringBuilder uri = apiUri("geocode");
|
||||
|
||||
// Since HSL is picky about the input we clean out any
|
||||
// character that isn't alphabetic, numeral, -, ', /
|
||||
// or a space. Those should be all chars needed for a
|
||||
// name.
|
||||
String constraintStr = constraint.toString().replaceAll("[^\\p{Ll}\\p{Lu}\\p{Lt}\\p{Lo}\\p{Nd}\\d-'/ ]", "");
|
||||
uri.append("&key=").append(URLEncoder.encode(constraintStr, "utf-8"));
|
||||
final AtomicReference<SuggestLocationsResult> result = new AtomicReference<SuggestLocationsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
is = httpClient.getInputStream(uri.toString());
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT);
|
||||
final List<SuggestedLocation> locations = new ArrayList<SuggestedLocation>();
|
||||
|
||||
if (firstChars.isEmpty())
|
||||
return new SuggestLocationsResult(header, locations);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.charStream());
|
||||
|
||||
XmlPullUtil.enter(pp, "response");
|
||||
|
||||
|
@ -393,18 +384,21 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
if (shortCode != null)
|
||||
name = name + " (" + shortCode + ")";
|
||||
|
||||
locations.add(new SuggestedLocation(new Location(type, id, pt.lat, pt.lon, null, name), weight));
|
||||
locations
|
||||
.add(new SuggestedLocation(new Location(type, id, pt.lat, pt.lon, null, name), weight));
|
||||
weight -= 1;
|
||||
}
|
||||
|
||||
return new SuggestLocationsResult(header, locations);
|
||||
result.set(new SuggestLocationsResult(header, locations));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()));
|
||||
return result.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class QueryTripsHslContext implements QueryTripsContext {
|
||||
|
@ -553,23 +547,18 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
}
|
||||
|
||||
private QueryTripsResult queryHslTrips(final Location from, final Location via, final Location to,
|
||||
QueryTripsHslContext context, Date date, boolean later) throws IOException {
|
||||
final QueryTripsHslContext context, Date date, final boolean later) throws IOException {
|
||||
final StringBuilder uri = new StringBuilder(context.uri);
|
||||
|
||||
uri.append("&date=").append(new SimpleDateFormat("yyyyMMdd").format(date));
|
||||
uri.append("&time=").append(new SimpleDateFormat("HHmm").format(date));
|
||||
final AtomicReference<QueryTripsResult> result = new AtomicReference<QueryTripsResult>();
|
||||
|
||||
InputStream is = null;
|
||||
String firstChars = null;
|
||||
|
||||
context.date = date;
|
||||
|
||||
final HttpClient.Callback callback = new HttpClient.Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
try {
|
||||
is = httpClient.getInputStream(uri.toString());
|
||||
firstChars = HttpClient.peekFirstChars(is);
|
||||
|
||||
final XmlPullParser pp = parserFactory.newPullParser();
|
||||
pp.setInput(is, null);
|
||||
pp.setInput(body.charStream());
|
||||
|
||||
XmlPullUtil.enter(pp, "response");
|
||||
|
||||
|
@ -662,17 +651,18 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
if (legType.equals("walk")) {
|
||||
// ugly hack to set the name of the last arrival
|
||||
if (arrival != null && arrival.name == null) {
|
||||
arrival = new Location(arrival.type, arrival.id, arrival.lat, arrival.lon, arrival.place,
|
||||
to.name);
|
||||
arrival = new Location(arrival.type, arrival.id, arrival.lat, arrival.lon,
|
||||
arrival.place, to.name);
|
||||
}
|
||||
|
||||
legs.add(new Trip.Individual(Trip.Individual.Type.WALK, departure, departureTime, arrival,
|
||||
arrivalTime, path, distance));
|
||||
legs.add(new Trip.Individual(Trip.Individual.Type.WALK, departure, departureTime,
|
||||
arrival, arrivalTime, path, distance));
|
||||
} else {
|
||||
Stop arrivalStop = null;
|
||||
if (stops.size() > 0) {
|
||||
Stop last = stops.getLast();
|
||||
arrivalStop = new Stop(last.location, false, last.plannedArrivalTime, null, null, null);
|
||||
arrivalStop = new Stop(last.location, false, last.plannedArrivalTime, null, null,
|
||||
null);
|
||||
stops.removeLast();
|
||||
}
|
||||
|
||||
|
@ -706,12 +696,17 @@ public class HslProvider extends AbstractNetworkProvider {
|
|||
if (context.prevDate == null || firstDate.before(context.prevDate))
|
||||
context.prevDate = firstDate;
|
||||
context.trips = trips;
|
||||
return new QueryTripsResult(header, uri.toString(), from, via, to, context, trips);
|
||||
|
||||
result.set(new QueryTripsResult(header, uri.toString(), from, via, to, context, trips));
|
||||
} catch (final XmlPullParserException x) {
|
||||
throw new ParserException("cannot parse xml: " + firstChars, x);
|
||||
} finally {
|
||||
if (is != null)
|
||||
is.close();
|
||||
throw new ParserException("cannot parse xml: " + bodyPeek, x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
context.date = date;
|
||||
|
||||
httpClient.getInputStream(callback, HttpUrl.parse(uri.toString()));
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,8 @@ import de.schildbach.pte.dto.StationDepartures;
|
|||
import de.schildbach.pte.dto.Style;
|
||||
import de.schildbach.pte.util.ParserUtils;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
|
@ -171,7 +173,7 @@ public class InvgProvider extends AbstractHafasProvider {
|
|||
// scrape page
|
||||
final StringBuilder uri = new StringBuilder(stationBoardEndpoint);
|
||||
appendXmlStationBoardParameters(uri, time, stationId, maxDepartures, false, null);
|
||||
final CharSequence page = httpClient.get(uri.toString());
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()));
|
||||
|
||||
// parse page
|
||||
final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page);
|
||||
|
|
|
@ -51,6 +51,8 @@ import de.schildbach.pte.dto.ResultHeader;
|
|||
import de.schildbach.pte.dto.StationDepartures;
|
||||
import de.schildbach.pte.util.ParserUtils;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
|
@ -134,7 +136,7 @@ public class SeptaProvider extends AbstractHafasProvider {
|
|||
// scrape page
|
||||
final StringBuilder uri = new StringBuilder(stationBoardEndpoint);
|
||||
appendXmlStationBoardParameters(uri, time, stationId, maxDepartures, false, null);
|
||||
final CharSequence page = httpClient.get(uri.toString());
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()));
|
||||
|
||||
// parse page
|
||||
final Matcher mPageCoarse = P_DEPARTURES_PAGE_COARSE.matcher(page);
|
||||
|
|
|
@ -73,6 +73,8 @@ import de.schildbach.pte.dto.Trip;
|
|||
import de.schildbach.pte.dto.Trip.Leg;
|
||||
import de.schildbach.pte.util.ParserUtils;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Michael Dyrna
|
||||
*/
|
||||
|
@ -370,7 +372,7 @@ public class VrsProvider extends AbstractNetworkProvider {
|
|||
uri.append("&s=").append(Math.min(16, maxLocations)); // artificial server limit
|
||||
}
|
||||
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final List<Location> locations = new ArrayList<Location>();
|
||||
|
@ -427,7 +429,7 @@ public class VrsProvider extends AbstractNetworkProvider {
|
|||
uri.append("&t=");
|
||||
appendDate(uri, time);
|
||||
}
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -514,7 +516,7 @@ public class VrsProvider extends AbstractNetworkProvider {
|
|||
final StringBuilder uri = new StringBuilder(API_BASE);
|
||||
uri.append("?eID=tx_vrsinfo_his_info&i=").append(ParserUtils.urlEncode(stationId));
|
||||
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final JSONObject head = new JSONObject(page.toString());
|
||||
|
@ -573,7 +575,7 @@ public class VrsProvider extends AbstractNetworkProvider {
|
|||
final String uri = API_BASE + "?eID=tx_vrsinfo_ass2_objects&sc=" + sc + "&ac=" + ac + "&pc=" + ac + "&t=sap&q="
|
||||
+ ParserUtils.urlEncode(new Location(LocationType.ANY, null, null, constraint.toString()).name);
|
||||
|
||||
final CharSequence page = httpClient.get(uri, Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri), Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final List<SuggestedLocation> locations = new ArrayList<SuggestedLocation>();
|
||||
|
@ -691,7 +693,7 @@ public class VrsProvider extends AbstractNetworkProvider {
|
|||
uri.append("p");
|
||||
}
|
||||
|
||||
final CharSequence page = httpClient.get(uri.toString(), Charsets.UTF_8);
|
||||
final CharSequence page = httpClient.get(HttpUrl.parse(uri.toString()), Charsets.UTF_8);
|
||||
|
||||
try {
|
||||
final List<Trip> trips = new ArrayList<Trip>();
|
||||
|
|
|
@ -18,45 +18,32 @@
|
|||
package de.schildbach.pte.exception;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
|
||||
import de.schildbach.pte.util.HttpClient;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class AbstractHttpException extends IOException {
|
||||
private final URL url;
|
||||
private final Reader errorReader;
|
||||
private final HttpUrl url;
|
||||
private final CharSequence bodyPeek;
|
||||
|
||||
public AbstractHttpException(final URL url) {
|
||||
public AbstractHttpException(final HttpUrl url) {
|
||||
this(url, null);
|
||||
}
|
||||
|
||||
public AbstractHttpException(final URL url, final Reader errorReader) {
|
||||
public AbstractHttpException(final HttpUrl url, final CharSequence bodyPeek) {
|
||||
super(url.toString());
|
||||
this.url = url;
|
||||
this.errorReader = errorReader;
|
||||
this.bodyPeek = bodyPeek;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
public HttpUrl getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public Reader getErrorReader() {
|
||||
return errorReader;
|
||||
}
|
||||
|
||||
public CharSequence scrapeErrorStream() throws IOException {
|
||||
if (errorReader == null)
|
||||
return null;
|
||||
|
||||
final StringBuilder error = new StringBuilder(HttpClient.SCRAPE_INITIAL_CAPACITY);
|
||||
HttpClient.copy(errorReader, error);
|
||||
errorReader.close();
|
||||
|
||||
return error;
|
||||
public CharSequence getBodyPeek() {
|
||||
return bodyPeek;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,14 @@
|
|||
|
||||
package de.schildbach.pte.exception;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class BlockedException extends AbstractHttpException {
|
||||
public BlockedException(final URL url, final Reader errorReader) {
|
||||
super(url, errorReader);
|
||||
public BlockedException(final HttpUrl url, final CharSequence bodyPeek) {
|
||||
super(url, bodyPeek);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,14 @@
|
|||
|
||||
package de.schildbach.pte.exception;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class InternalErrorException extends AbstractHttpException {
|
||||
public InternalErrorException(final URL url, final Reader errorReader) {
|
||||
super(url, errorReader);
|
||||
public InternalErrorException(final HttpUrl url, final CharSequence bodyPeek) {
|
||||
super(url, bodyPeek);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,15 +17,14 @@
|
|||
|
||||
package de.schildbach.pte.exception;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NotFoundException extends AbstractHttpException {
|
||||
public NotFoundException(final URL url, final Reader errorReader) {
|
||||
super(url, errorReader);
|
||||
public NotFoundException(final HttpUrl url, final CharSequence bodyPeek) {
|
||||
super(url, bodyPeek);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,21 +17,21 @@
|
|||
|
||||
package de.schildbach.pte.exception;
|
||||
|
||||
import java.net.URL;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class UnexpectedRedirectException extends AbstractHttpException {
|
||||
private final URL redirectedUrl;
|
||||
private final HttpUrl redirectedUrl;
|
||||
|
||||
public UnexpectedRedirectException(final URL originalUrl, final URL redirectedUrl) {
|
||||
public UnexpectedRedirectException(final HttpUrl originalUrl, final HttpUrl redirectedUrl) {
|
||||
super(originalUrl);
|
||||
this.redirectedUrl = redirectedUrl;
|
||||
}
|
||||
|
||||
public URL getRedirectedUrl() {
|
||||
public HttpUrl getRedirectedUrl() {
|
||||
return redirectedUrl;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,27 +17,19 @@
|
|||
|
||||
package de.schildbach.pte.util;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.net.HttpCookie;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -51,6 +43,18 @@ import de.schildbach.pte.exception.NotFoundException;
|
|||
import de.schildbach.pte.exception.SessionExpiredException;
|
||||
import de.schildbach.pte.exception.UnexpectedRedirectException;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
|
@ -61,15 +65,33 @@ public final class HttpClient {
|
|||
@Nullable
|
||||
private String sessionCookieName = null;
|
||||
@Nullable
|
||||
private HttpCookie sessionCookie = null;
|
||||
private Cookie sessionCookie = null;
|
||||
private boolean sslAcceptAllHostnames = false;
|
||||
|
||||
private static final OkHttpClient OKHTTP_CLIENT;
|
||||
static {
|
||||
final HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(
|
||||
new HttpLoggingInterceptor.Logger() {
|
||||
@Override
|
||||
public void log(final String message) {
|
||||
log.debug(message);
|
||||
}
|
||||
});
|
||||
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
|
||||
|
||||
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
builder.followRedirects(false);
|
||||
builder.followSslRedirects(true);
|
||||
builder.connectTimeout(5, TimeUnit.SECONDS);
|
||||
builder.writeTimeout(5, TimeUnit.SECONDS);
|
||||
builder.readTimeout(15, TimeUnit.SECONDS);
|
||||
builder.addNetworkInterceptor(loggingInterceptor);
|
||||
OKHTTP_CLIENT = builder.build();
|
||||
}
|
||||
|
||||
private static final String SCRAPE_ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
|
||||
public static final int SCRAPE_INITIAL_CAPACITY = 4096;
|
||||
private static final int SCRAPE_COPY_SIZE = 2048;
|
||||
private static final int SCRAPE_PEEK_SIZE = 4096;
|
||||
private static final int SCRAPE_CONNECT_TIMEOUT = 5000;
|
||||
private static final int SCRAPE_READ_TIMEOUT = 15000;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpClient.class);
|
||||
|
||||
|
@ -89,199 +111,127 @@ public final class HttpClient {
|
|||
this.sslAcceptAllHostnames = sslAcceptAllHostnames;
|
||||
}
|
||||
|
||||
public CharSequence get(final String url) throws IOException {
|
||||
public CharSequence get(final HttpUrl url) throws IOException {
|
||||
return get(url, null);
|
||||
}
|
||||
|
||||
public CharSequence get(final String urlStr, final Charset requestEncoding) throws IOException {
|
||||
return get(urlStr, null, null, requestEncoding);
|
||||
public CharSequence get(final HttpUrl url, final Charset requestEncoding) throws IOException {
|
||||
return get(url, null, null, requestEncoding);
|
||||
}
|
||||
|
||||
public CharSequence get(final String urlStr, final String postRequest, final String requestContentType,
|
||||
public CharSequence get(final HttpUrl url, final String postRequest, final String requestContentType,
|
||||
Charset requestEncoding) throws IOException {
|
||||
if (requestEncoding == null)
|
||||
requestEncoding = Charsets.ISO_8859_1;
|
||||
|
||||
final StringBuilder buffer = new StringBuilder(SCRAPE_INITIAL_CAPACITY);
|
||||
final InputStream is = getInputStream(urlStr, postRequest, requestContentType, requestEncoding, null);
|
||||
final Reader pageReader = new InputStreamReader(is, requestEncoding);
|
||||
copy(pageReader, buffer);
|
||||
pageReader.close();
|
||||
final Callback callback = new Callback() {
|
||||
@Override
|
||||
public void onSuccessful(final CharSequence bodyPeek, final ResponseBody body) throws IOException {
|
||||
buffer.append(body.string());
|
||||
}
|
||||
};
|
||||
getInputStream(callback, url, postRequest, requestContentType, requestEncoding, null);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public InputStream getInputStream(final String url) throws IOException {
|
||||
return getInputStream(url, null, null);
|
||||
public interface Callback {
|
||||
void onSuccessful(CharSequence bodyPeek, ResponseBody body) throws IOException;
|
||||
}
|
||||
|
||||
public InputStream getInputStream(final String urlStr, final Charset requestEncoding, final String referer)
|
||||
throws IOException {
|
||||
return getInputStream(urlStr, null, null, requestEncoding, referer);
|
||||
public void getInputStream(final Callback callback, final HttpUrl url) throws IOException {
|
||||
getInputStream(callback, url, null, null);
|
||||
}
|
||||
|
||||
public InputStream getInputStream(final String urlStr, final String postRequest, final String requestContentType,
|
||||
Charset requestEncoding, final String referer) throws IOException {
|
||||
log.debug("{}: {}", postRequest != null ? "POST" : "GET", urlStr);
|
||||
public void getInputStream(final Callback callback, final HttpUrl url, final Charset requestEncoding,
|
||||
final String referer) throws IOException {
|
||||
getInputStream(callback, url, null, null, requestEncoding, referer);
|
||||
}
|
||||
|
||||
public void getInputStream(final Callback callback, final HttpUrl url, final String postRequest,
|
||||
final String requestContentType, Charset requestEncoding, final String referer) throws IOException {
|
||||
if (requestEncoding == null)
|
||||
requestEncoding = Charsets.ISO_8859_1;
|
||||
|
||||
int tries = 3;
|
||||
|
||||
while (true) {
|
||||
final URL url = new URL(urlStr);
|
||||
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
if (connection instanceof HttpsURLConnection && sslAcceptAllHostnames)
|
||||
((HttpsURLConnection) connection).setHostnameVerifier(SSL_ACCEPT_ALL_HOSTNAMES);
|
||||
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(postRequest != null);
|
||||
connection.setConnectTimeout(SCRAPE_CONNECT_TIMEOUT);
|
||||
connection.setReadTimeout(SCRAPE_READ_TIMEOUT);
|
||||
for (final Map.Entry<String, String> entry : headers.entrySet())
|
||||
connection.addRequestProperty(entry.getKey(), entry.getValue());
|
||||
final Request.Builder request = new Request.Builder();
|
||||
request.url(url);
|
||||
request.headers(Headers.of(headers));
|
||||
if (postRequest != null)
|
||||
request.post(RequestBody.create(MediaType.parse(requestContentType), postRequest));
|
||||
request.header("Accept", SCRAPE_ACCEPT);
|
||||
if (userAgent != null)
|
||||
connection.addRequestProperty("User-Agent", userAgent);
|
||||
connection.addRequestProperty("Accept", SCRAPE_ACCEPT);
|
||||
connection.addRequestProperty("Accept-Encoding", "gzip");
|
||||
// workaround to disable Vodafone compression
|
||||
connection.addRequestProperty("Cache-Control", "no-cache");
|
||||
|
||||
request.header("User-Agent", userAgent);
|
||||
if (referer != null)
|
||||
connection.addRequestProperty("Referer", referer);
|
||||
request.header("Referer", referer);
|
||||
final Cookie sessionCookie = this.sessionCookie;
|
||||
if (sessionCookie != null && sessionCookie.name().equals(sessionCookieName))
|
||||
request.header("Cookie", sessionCookie.toString());
|
||||
|
||||
final HttpCookie sessionCookie = this.sessionCookie;
|
||||
if (sessionCookie != null && sessionCookie.getName().equals(sessionCookieName))
|
||||
connection.addRequestProperty("Cookie", sessionCookie.toString());
|
||||
final OkHttpClient okHttpClient;
|
||||
if (sslAcceptAllHostnames)
|
||||
okHttpClient = OKHTTP_CLIENT.newBuilder().hostnameVerifier(SSL_ACCEPT_ALL_HOSTNAMES).build();
|
||||
else
|
||||
okHttpClient = OKHTTP_CLIENT;
|
||||
|
||||
if (postRequest != null) {
|
||||
final byte[] postRequestBytes = postRequest.getBytes(requestEncoding.name());
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Content-Type", requestContentType);
|
||||
connection.addRequestProperty("Content-Length", Integer.toString(postRequestBytes.length));
|
||||
|
||||
final OutputStream os = connection.getOutputStream();
|
||||
os.write(postRequestBytes);
|
||||
os.close();
|
||||
}
|
||||
|
||||
final int responseCode = connection.getResponseCode();
|
||||
final Call call = okHttpClient.newCall(request.build());
|
||||
Response response = null;
|
||||
try {
|
||||
response = call.execute();
|
||||
final int responseCode = response.code();
|
||||
final String bodyPeek = response.peekBody(SCRAPE_PEEK_SIZE).string().replaceAll("\\p{C}", "");
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
final String contentType = connection.getContentType();
|
||||
final String contentEncoding = connection.getContentEncoding();
|
||||
|
||||
InputStream is = new BufferedInputStream(connection.getInputStream());
|
||||
|
||||
if ("gzip".equalsIgnoreCase(contentEncoding)
|
||||
|| "application/octet-stream".equalsIgnoreCase(contentType))
|
||||
is = wrapGzip(is);
|
||||
|
||||
if (!url.getHost().equals(connection.getURL().getHost()))
|
||||
throw new UnexpectedRedirectException(url, connection.getURL());
|
||||
|
||||
final String firstChars = peekFirstChars(is);
|
||||
|
||||
final URL redirectUrl = testRedirect(url, firstChars);
|
||||
final HttpUrl redirectUrl = testRedirect(url, bodyPeek);
|
||||
if (redirectUrl != null)
|
||||
throw new UnexpectedRedirectException(url, redirectUrl);
|
||||
|
||||
if (testExpired(firstChars))
|
||||
if (testExpired(bodyPeek))
|
||||
throw new SessionExpiredException();
|
||||
|
||||
if (testInternalError(firstChars))
|
||||
throw new InternalErrorException(url, new InputStreamReader(is, requestEncoding));
|
||||
if (testInternalError(bodyPeek))
|
||||
throw new InternalErrorException(url, bodyPeek);
|
||||
|
||||
// save cookie
|
||||
if (sessionCookieName != null) {
|
||||
c: for (final Map.Entry<String, List<String>> entry : connection.getHeaderFields().entrySet()) {
|
||||
if ("set-cookie".equalsIgnoreCase(entry.getKey())
|
||||
|| "set-cookie2".equalsIgnoreCase(entry.getKey())) {
|
||||
for (final String value : entry.getValue()) {
|
||||
for (final HttpCookie cookie : HttpCookie.parse(value)) {
|
||||
if (cookie.getName().equals(sessionCookieName)) {
|
||||
final List<Cookie> cookies = Cookie.parseAll(url, response.headers());
|
||||
for (final Iterator<Cookie> i = cookies.iterator(); i.hasNext();) {
|
||||
final Cookie cookie = i.next();
|
||||
if (cookie.name().equals(sessionCookieName)) {
|
||||
this.sessionCookie = cookie;
|
||||
break c;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return is;
|
||||
callback.onSuccessful(bodyPeek, response.body());
|
||||
return;
|
||||
} else if (responseCode == HttpURLConnection.HTTP_BAD_REQUEST
|
||||
|| responseCode == HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
|| responseCode == HttpURLConnection.HTTP_FORBIDDEN
|
||||
|| responseCode == HttpURLConnection.HTTP_NOT_ACCEPTABLE
|
||||
|| responseCode == HttpURLConnection.HTTP_UNAVAILABLE) {
|
||||
throw new BlockedException(url, new InputStreamReader(connection.getErrorStream(), requestEncoding));
|
||||
throw new BlockedException(url, bodyPeek);
|
||||
} else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
|
||||
throw new NotFoundException(url, new InputStreamReader(connection.getErrorStream(), requestEncoding));
|
||||
throw new NotFoundException(url, bodyPeek);
|
||||
} else if (responseCode == HttpURLConnection.HTTP_MOVED_PERM
|
||||
|| responseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
|
||||
throw new UnexpectedRedirectException(url, connection.getURL());
|
||||
throw new UnexpectedRedirectException(url, HttpUrl.parse(response.header("Location")));
|
||||
} else if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
|
||||
throw new InternalErrorException(url,
|
||||
new InputStreamReader(connection.getErrorStream(), requestEncoding));
|
||||
throw new InternalErrorException(url, bodyPeek);
|
||||
} else {
|
||||
final String message = "got response: " + responseCode + " " + connection.getResponseMessage();
|
||||
final String message = "got response: " + responseCode + " " + response.message();
|
||||
if (tries-- > 0)
|
||||
log.info("{}, retrying...", message);
|
||||
else
|
||||
throw new IOException(message + ": " + url);
|
||||
}
|
||||
} finally {
|
||||
if (response != null)
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static final long copy(final Reader reader, final StringBuilder builder) throws IOException {
|
||||
final char[] buffer = new char[SCRAPE_COPY_SIZE];
|
||||
long count = 0;
|
||||
int n = 0;
|
||||
while (-1 != (n = reader.read(buffer))) {
|
||||
builder.append(buffer, 0, n);
|
||||
count += n;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private static InputStream wrapGzip(final InputStream is) throws IOException {
|
||||
is.mark(2);
|
||||
final int byte0 = is.read();
|
||||
final int byte1 = is.read();
|
||||
is.reset();
|
||||
|
||||
// check for gzip header
|
||||
if (byte0 == 0x1f && byte1 == 0x8b) {
|
||||
final BufferedInputStream is2 = new BufferedInputStream(new GZIPInputStream(is));
|
||||
is2.mark(2);
|
||||
final int byte0_2 = is2.read();
|
||||
final int byte1_2 = is2.read();
|
||||
is2.reset();
|
||||
|
||||
// check for gzip header again
|
||||
if (byte0_2 == 0x1f && byte1_2 == 0x8b) {
|
||||
// double gzipped
|
||||
return new BufferedInputStream(new GZIPInputStream(is2));
|
||||
} else {
|
||||
// gzipped
|
||||
return is2;
|
||||
}
|
||||
} else {
|
||||
// uncompressed
|
||||
return is;
|
||||
}
|
||||
}
|
||||
|
||||
public static String peekFirstChars(final InputStream is) throws IOException {
|
||||
is.mark(SCRAPE_PEEK_SIZE);
|
||||
final byte[] firstBytes = new byte[SCRAPE_PEEK_SIZE];
|
||||
final int read = is.read(firstBytes);
|
||||
if (read == -1)
|
||||
return "";
|
||||
is.reset();
|
||||
return new String(firstBytes, 0, read).replaceAll("\\p{C}", "");
|
||||
}
|
||||
|
||||
private static final Pattern P_REDIRECT_HTTP_EQUIV = Pattern.compile(
|
||||
|
@ -291,16 +241,16 @@ public final class HttpClient {
|
|||
"<script\\s+(?:type=\"text/javascript\"|language=\"javascript\")>\\s*(?:window.location|location.href)\\s*=\\s*\"([^\"]+)\"",
|
||||
Pattern.CASE_INSENSITIVE);
|
||||
|
||||
public static URL testRedirect(final URL context, final String content) throws MalformedURLException {
|
||||
public static HttpUrl testRedirect(final HttpUrl base, final String content) {
|
||||
// check for redirect by http-equiv meta tag header
|
||||
final Matcher mHttpEquiv = P_REDIRECT_HTTP_EQUIV.matcher(content);
|
||||
if (mHttpEquiv.find())
|
||||
return new URL(context, mHttpEquiv.group(1));
|
||||
return base.resolve(mHttpEquiv.group(1));
|
||||
|
||||
// check for redirect by window.location javascript
|
||||
final Matcher mScript = P_REDIRECT_SCRIPT.matcher(content);
|
||||
if (mScript.find())
|
||||
return new URL(context, mScript.group(1));
|
||||
return base.resolve(mScript.group(1));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -21,51 +21,51 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
/**
|
||||
* @author Andreas Schildbach
|
||||
*/
|
||||
public class HttpClientTest {
|
||||
private URL context;
|
||||
private HttpUrl base;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
context = new URL("http://example.com");
|
||||
base = HttpUrl.parse("http://example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vodafoneRedirect() throws Exception {
|
||||
final URL url = HttpClient.testRedirect(context,
|
||||
final HttpUrl url = HttpClient.testRedirect(base,
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE html PUBLIC \"-//WAPFORUM//DTD XHTML Mobile 1.1//EN \" \"http://www.openmobilealliance.org/tech/DTD/xhtml-mobile11.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"; xml:lang=\"en\"><head><title>Vodafone Center</title><meta http-equiv=\"Cache-Control\" content=\"no-cache\"/><meta http-equiv=\"refresh\" content=\"1;URL=https://center.vodafone.de/vfcenter/index.html?targetUrl=http%3A%2F%2Fwww.fahrinfo-berlin.de/Fahrinfo/bin/query.bin/dn%3fstart=Suchen&REQ0JourneyStopsS0ID=A%253D1%2540L%253D9083301&REQ0JourneyStopsZ0ID=A%253D1%2540L%253D9195009&REQ0HafasSearchForw=1&REQ0JourneyDate=16.06.14&REQ0JourneyTime=16%253A32&REQ0JourneyProduct_prod_list_1=11111011&h2g-direct=11&L=vs_oeffi\"/><style type=\"text/css\">*{border:none;font-family:Arial,Helvetica,sans-serif} body{font-size:69%;line-height:140%;background-color:#F4F4F4 !important}</style></head><body><h1>Sie werden weitergeleitet ...</h1><p>Sollten Sie nicht weitergeleitet werden, klicken Sie bitte <a href=\"https://center.vodafo");
|
||||
assertNotNull(url);
|
||||
assertEquals("center.vodafone.de", url.getHost());
|
||||
assertEquals("center.vodafone.de", url.host());
|
||||
}
|
||||
|
||||
public void kabelDeutschlandRedirect() throws Exception {
|
||||
final URL url = HttpClient.testRedirect(context,
|
||||
final HttpUrl url = HttpClient.testRedirect(base,
|
||||
"<script type=\"text/javascript\"> window.location = \"http://www.hotspot.kabeldeutschland.de/portal/?RequestedURI=http%3A%2F%2Fwww.fahrinfo-berlin.de%2FFahrinfo%2Fbin%2Fajax-getstop.bin%2Fdny%3Fgetstop%3D1%26REQ0JourneyStopsS0A%3D255%26REQ0JourneyStopsS0G%3Dgneisenustra%25DFe%3F%26js%3Dtrue&RedirectReason=Policy&RedirectAqpId=100&DiscardAqpId=100&SubscriberId=4fa432d4a653e5f8b2acb27aa862f98d&SubscriberType=ESM&ClientIP=10.136.25.241&SystemId=10.143.181.2-1%2F2&GroupId=1&PartitionId=2&Application=Unknown&ApplicationGroup=Unknown\" </script>");
|
||||
assertNotNull(url);
|
||||
assertEquals("www.hotspot.kabeldeutschland.de", url.getHost());
|
||||
assertEquals("www.hotspot.kabeldeutschland.de", url.host());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tplinkRedirect() throws Exception {
|
||||
final URL url = HttpClient.testRedirect(context,
|
||||
final HttpUrl url = HttpClient.testRedirect(base,
|
||||
"<body><script language=\"javaScript\">location.href=\"http://tplinkextender.net/\";</script></body></html>");
|
||||
assertNotNull(url);
|
||||
assertEquals("tplinkextender.net", url.getHost());
|
||||
assertEquals("tplinkextender.net", url.host());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mshtmlRedirect() throws Exception {
|
||||
final URL url = HttpClient.testRedirect(context,
|
||||
final HttpUrl url = HttpClient.testRedirect(base,
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><HEAD><TITLE>HTML Redirection</TITLE><META http-equiv=Content-Type content=\"text/html; \"><META http-equiv=Refresh content=\"0;URL=/cgi-bin/index.cgi\"><META content=\"MSHTML 6.00.2900.2873\" name=GENERATOR></HEAD><BODY > <NOSCRIPT> If your browser can not redirect you to home page automatically.<br> Please click <a href=/cgi-bin/welcome.cgi?lang=0>here</a>. </NOSCRIPT></BODY></HTML>");
|
||||
assertNotNull(url);
|
||||
assertEquals("example.com", url.getHost());
|
||||
assertEquals("example.com", url.host());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue