From dc390eb5a407f491c14481ab9c87206ed09d0f27 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Wed, 31 Oct 2018 15:49:37 +0100 Subject: [PATCH] INVG: Switch to Hafas Client Interface. --- .../src/de/schildbach/pte/InvgProvider.java | 253 +----------------- .../de/schildbach/pte/util/ParserUtils.java | 2 - .../pte/live/InvgProviderLiveTest.java | 25 +- .../pte/live/secrets.properties.template | 1 + 4 files changed, 26 insertions(+), 255 deletions(-) diff --git a/enabler/src/de/schildbach/pte/InvgProvider.java b/enabler/src/de/schildbach/pte/InvgProvider.java index a3de7b0a..6b8fe464 100644 --- a/enabler/src/de/schildbach/pte/InvgProvider.java +++ b/enabler/src/de/schildbach/pte/InvgProvider.java @@ -17,67 +17,28 @@ package de.schildbach.pte; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; -import java.util.GregorianCalendar; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Set; import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.Nullable; - -import com.google.common.base.Charsets; -import com.google.common.base.Strings; - -import de.schildbach.pte.dto.Departure; -import de.schildbach.pte.dto.Line; -import de.schildbach.pte.dto.Location; -import de.schildbach.pte.dto.LocationType; -import de.schildbach.pte.dto.Position; import de.schildbach.pte.dto.Product; -import de.schildbach.pte.dto.QueryDeparturesResult; -import de.schildbach.pte.dto.QueryDeparturesResult.Status; -import de.schildbach.pte.dto.QueryTripsContext; -import de.schildbach.pte.dto.QueryTripsResult; -import de.schildbach.pte.dto.ResultHeader; -import de.schildbach.pte.dto.StationDepartures; import de.schildbach.pte.dto.Style; -import de.schildbach.pte.util.ParserUtils; import okhttp3.HttpUrl; /** * @author Andreas Schildbach */ -public class InvgProvider extends AbstractHafasLegacyProvider { +public class InvgProvider extends AbstractHafasClientInterfaceProvider { private static final HttpUrl API_BASE = HttpUrl.parse("https://fpa.invg.de/bin/"); - // http://invg.hafas.de/bin/ - private static final Product[] PRODUCTS_MAP = { null, null, null, null, null, null, null, null, null, null }; - private static final long PARSER_DAY_ROLLOVER_THRESHOLD_MS = 12 * 60 * 60 * 1000; + private static final Product[] PRODUCTS_MAP = { Product.BUS, null, null, Product.REGIONAL_TRAIN }; - public InvgProvider() { - super(NetworkId.INVG, API_BASE, "dn", PRODUCTS_MAP); - setRequestUrlEncoding(Charsets.UTF_8); - setStationBoardCanDoEquivs(false); - setJsonNearbyLocationsEncoding(Charsets.UTF_8); + public InvgProvider(final String apiAuthorization) { + super(NetworkId.INVG, API_BASE, PRODUCTS_MAP); + setApiVersion("1.13"); + setApiClient("{\"id\":\"INVG\",\"type\":\"AND\"}"); + setApiAuthorization(apiAuthorization); setStyles(STYLES); - setExtXmlEndpoint(API_BASE.newBuilder().addPathSegment("extxml.exe").build()); - } - - @Override - protected boolean hasCapability(final Capability capability) { - if (capability == Capability.TRIPS) - return false; - else - return super.hasCapability(capability); } private static final String[] PLACES = { "Ingolstadt", "München" }; @@ -113,206 +74,6 @@ public class InvgProvider extends AbstractHafasLegacyProvider { return super.splitStationName(address); } - private static final Pattern P_DEPARTURES_HEAD_COARSE = Pattern.compile(".*?" // - + "(?:" // - + "
.*?
.*?(
.*?
.*?
.*?
).*?
.*?" // - + "
.*?input=(\\d+).*?" // locationId - + "(?:(.*?)
|(verkehren an dieser Haltestelle keine))"// - + "|(Eingabe kann nicht interpretiert)|(Verbindung zum Server konnte leider nicht hergestellt werden|kann vom Server derzeit leider nicht bearbeitet werden))" // - + ".*?" // - , Pattern.DOTALL); - private static final Pattern P_DEPARTURES_HEAD_FINE = Pattern.compile( - ".*?" // - + "(.*?)<.*?" // location - + "\n(\\d{2}\\.\\d{2}\\.\\d{2}).*?" // date - + "Abfahrt (\\d{1,2}:\\d{2}).*?" // time - , Pattern.DOTALL); - private static final Pattern P_DEPARTURES_COARSE = Pattern.compile("(.*?)", - Pattern.DOTALL); - private static final Pattern P_DEPARTURES_FINE = Pattern.compile( - ".*?" // - + "(\\d{1,2}:\\d{2})\n" // plannedTime - + "(?:\n" // - + "(?: |(pünktlich|\\d{1,2}:\\d{2}))\n\n" // predictedTime - + ")?.*?" // - + "]*>\\s*(.*?)\\s*\n" // - + "]*>" // destinationId - + "\\s*(.*?)\\s*\n" // destination - + ".*?" // - + "(?:\n(" + ParserUtils.P_PLATFORM + ").*?)?" // position - , Pattern.DOTALL); - - @Override - public QueryDeparturesResult queryDepartures(final String stationId, final @Nullable Date time, - final int maxDepartures, final boolean equivs) throws IOException { - checkNotNull(Strings.emptyToNull(stationId)); - - final ResultHeader header = new ResultHeader(network, SERVER_PRODUCT); - final QueryDeparturesResult result = new QueryDeparturesResult(header); - - // scrape page - final HttpUrl.Builder url = stationBoardEndpoint.newBuilder().addPathSegment(apiLanguage); - appendXmlStationBoardParameters(url, time, stationId, maxDepartures, false, null); - final CharSequence page = httpClient.get(url.build()); - - // parse page - final Matcher mHeadCoarse = P_DEPARTURES_HEAD_COARSE.matcher(page); - if (mHeadCoarse.matches()) { - // messages - if (mHeadCoarse.group(4) != null) { - result.stationDepartures.add(new StationDepartures(new Location(LocationType.STATION, stationId), - Collections. emptyList(), null)); - return result; - } else if (mHeadCoarse.group(5) != null) - return new QueryDeparturesResult(header, Status.INVALID_STATION); - else if (mHeadCoarse.group(6) != null) - return new QueryDeparturesResult(header, Status.SERVICE_DOWN); - - final String locationId = mHeadCoarse.group(2); - - final Matcher mHeadFine = P_DEPARTURES_HEAD_FINE.matcher(mHeadCoarse.group(1)); - if (mHeadFine.matches()) { - final String[] placeAndName = splitStationName(ParserUtils.resolveEntities(mHeadFine.group(1))); - final Calendar currentTime = new GregorianCalendar(timeZone); - currentTime.clear(); - ParserUtils.parseGermanDate(currentTime, mHeadFine.group(2)); - ParserUtils.parseEuropeanTime(currentTime, mHeadFine.group(3)); - final List departures = new ArrayList<>(8); - String oldZebra = null; - - final Matcher mDepCoarse = P_DEPARTURES_COARSE.matcher(mHeadCoarse.group(3)); - while (mDepCoarse.find()) { - final String zebra = mDepCoarse.group(1); - if (oldZebra != null && zebra.equals(oldZebra)) - throw new IllegalArgumentException("missed row? last:" + zebra); - else - oldZebra = zebra; - - final Matcher mDepFine = P_DEPARTURES_FINE.matcher(mDepCoarse.group(2)); - if (mDepFine.matches()) { - final Calendar plannedTime = new GregorianCalendar(timeZone); - plannedTime.setTimeInMillis(currentTime.getTimeInMillis()); - ParserUtils.parseEuropeanTime(plannedTime, mDepFine.group(1)); - - if (plannedTime.getTimeInMillis() - - currentTime.getTimeInMillis() < -PARSER_DAY_ROLLOVER_THRESHOLD_MS) - plannedTime.add(Calendar.DAY_OF_MONTH, 1); - - final Calendar predictedTime; - final String prognosis = ParserUtils.resolveEntities(mDepFine.group(2)); - if (prognosis != null) { - predictedTime = new GregorianCalendar(timeZone); - if (prognosis.equals("pünktlich")) { - predictedTime.setTimeInMillis(plannedTime.getTimeInMillis()); - } else { - predictedTime.setTimeInMillis(currentTime.getTimeInMillis()); - ParserUtils.parseEuropeanTime(predictedTime, prognosis); - } - } else { - predictedTime = null; - } - - final String lineType = mDepFine.group(3); - - final Line line = parseLine(lineType, ParserUtils.resolveEntities(mDepFine.group(4)), false); - - final String destinationId = mDepFine.group(5); - final String destinationName = ParserUtils.resolveEntities(mDepFine.group(6)); - final Location destination; - if (destinationId != null) { - final String[] destinationPlaceAndName = splitStationName(destinationName); - destination = new Location(LocationType.STATION, destinationId, destinationPlaceAndName[0], - destinationPlaceAndName[1]); - } else { - destination = new Location(LocationType.ANY, null, null, destinationName); - } - - final Position position = parsePosition(ParserUtils.resolveEntities(mDepFine.group(7))); - - final Departure dep = new Departure(plannedTime.getTime(), - predictedTime != null ? predictedTime.getTime() : null, line, position, destination, - null, null); - - if (!departures.contains(dep)) - departures.add(dep); - } else { - throw new IllegalArgumentException( - "cannot parse '" + mDepCoarse.group(2) + "' on " + stationId); - } - } - - result.stationDepartures.add(new StationDepartures( - new Location(LocationType.STATION, locationId, placeAndName[0], placeAndName[1]), departures, - null)); - return result; - } else { - throw new IllegalArgumentException("cannot parse '" + mHeadCoarse.group(1) + "' on " + stationId); - } - } else { - throw new IllegalArgumentException("cannot parse '" + page + "' on " + stationId); - } - } - - @Override - public QueryTripsResult queryTrips(final Location from, final @Nullable Location via, final Location to, - final Date date, final boolean dep, final @Nullable Set products, - final @Nullable Optimize optimize, final @Nullable WalkSpeed walkSpeed, - final @Nullable Accessibility accessibility, final @Nullable Set