2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.deutschebahn.internal.timetable;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.nio.file.Files;
19 import java.util.ArrayList;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Properties;
24 import java.util.function.Function;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.openhab.binding.deutschebahn.internal.timetable.TimetablesV1Impl.HttpCallable;
33 * Stub Implementation for {@link HttpCallable}, that provides Data for the selected station, date and hour from file
36 * @author Sönke Küper - initial contribution.
39 public class TimetableStubHttpCallable implements HttpCallable {
41 private static final Pattern PLAN_URL_PATTERN = Pattern
42 .compile("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/(\\d+)/(\\d+)/(\\d+)");
43 private static final Pattern FULL_CHANGES_URL_PATTERN = Pattern
44 .compile("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/fchg/(\\d+)");
45 private static final Pattern RECENT_CHANGES_URL_PATTERN = Pattern
46 .compile("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/rchg/(\\d+)");
48 private final File testdataDir;
49 private final List<String> requestedPlanUrls;
50 private final List<String> requestedFullChangesUrls;
51 private final List<String> requestedRecentChangesUrls;
53 // Allows simulation of available data.
54 // if not set all available files will be served.
55 private @Nullable Set<String> availableUrls = null;
57 public TimetableStubHttpCallable(File testdataDir) {
58 this.testdataDir = testdataDir;
59 this.requestedPlanUrls = new ArrayList<>();
60 this.requestedFullChangesUrls = new ArrayList<String>();
61 this.requestedRecentChangesUrls = new ArrayList<String>();
64 public void addAvailableUrl(String url) {
65 if (this.availableUrls == null) {
66 availableUrls = new HashSet<>();
68 this.availableUrls.add(url);
72 public String executeUrl( //
75 Properties httpHeaders, //
76 @Nullable InputStream content, //
77 @Nullable String contentType, //
78 int timeout) throws IOException {
79 final Matcher planMatcher = PLAN_URL_PATTERN.matcher(url);
80 if (planMatcher.matches()) {
81 requestedPlanUrls.add(url);
82 return processRequest(url, planMatcher, this::getPlanData);
85 final Matcher fullChangesMatcher = FULL_CHANGES_URL_PATTERN.matcher(url);
86 if (fullChangesMatcher.matches()) {
87 requestedFullChangesUrls.add(url);
88 return processRequest(url, fullChangesMatcher, this::getFullChanges);
91 final Matcher recentChangesMatcher = RECENT_CHANGES_URL_PATTERN.matcher(url);
92 if (recentChangesMatcher.matches()) {
93 requestedRecentChangesUrls.add(url);
94 return processRequest(url, recentChangesMatcher, this::getRecentChanges);
99 private String processRequest(String url, Matcher matcher, Function<Matcher, String> responseSupplier) {
100 if (availableUrls != null && !availableUrls.contains(url)) {
103 return responseSupplier.apply(matcher);
107 private String getPlanData(final Matcher planMatcher) {
108 final String evaNo = planMatcher.group(1);
109 final String day = planMatcher.group(2);
110 final String hour = planMatcher.group(3);
112 final File responseFile = new File(this.testdataDir, "plan/" + evaNo + "/" + day + "/" + hour + ".xml");
113 return serveFileContentIfExists(responseFile);
116 private String serveFileContentIfExists(File responseFile) {
117 if (!responseFile.exists()) {
122 return Files.readString(responseFile.toPath());
123 } catch (IOException e) {
124 throw new AssertionError(e);
128 private String getRecentChanges(Matcher recentChangesMatcher) {
129 final String evaNo = recentChangesMatcher.group(1);
130 File responseFile = new File(this.testdataDir, "rchg/" + evaNo + ".xml");
131 return serveFileContentIfExists(responseFile);
134 private String getFullChanges(Matcher fullChangesMatcher) {
135 final String evaNo = fullChangesMatcher.group(1);
136 File responseFile = new File(this.testdataDir, "fchg/" + evaNo + ".xml");
137 return serveFileContentIfExists(responseFile);
140 public List<String> getRequestedPlanUrls() {
141 return requestedPlanUrls;
144 public List<String> getRequestedFullChangesUrls() {
145 return requestedFullChangesUrls;
148 public List<String> getRequestedRecentChangesUrls() {
149 return requestedRecentChangesUrls;