Skip to content

Commit

Permalink
introduce custom exception class instead of RuntimeExceptions
Browse files Browse the repository at this point in the history
We now use a custom, checked exceptions on errors that can occur
with the API communication or configuration. instead of throwing an
unchecked IllegalStateException.
  • Loading branch information
stklcode committed Aug 12, 2020
1 parent b14d040 commit 1148734
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 55 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
### Changes
* Using native Java 11 HTTP client
* Client configuration with separate `UraClientConfiguration` class and builder
* Client throws custom checked exception `UraClientException` instead of runtime exceptions on errors (#10)


## 1.3.0 - 2019-12-04
Expand Down
129 changes: 85 additions & 44 deletions src/main/java/de/stklcode/pubtrans/ura/UraClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
package de.stklcode.pubtrans.ura;

import com.fasterxml.jackson.databind.ObjectMapper;
import de.stklcode.pubtrans.ura.exception.UraClientConfigurationException;
import de.stklcode.pubtrans.ura.exception.UraClientException;
import de.stklcode.pubtrans.ura.model.Message;
import de.stklcode.pubtrans.ura.model.Stop;
import de.stklcode.pubtrans.ura.model.Trip;
import de.stklcode.pubtrans.ura.reader.AsyncUraTripReader;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
Expand Down Expand Up @@ -207,8 +210,11 @@ public final Query forPosition(final Double latitude, final Double longitude, fi
* If forStops() and/or forLines() has been called, those will be used as filter.
*
* @return List of trips.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Trip> getTrips() {
public List<Trip> getTrips() throws UraClientException {
return getTrips(new Query(), null);
}

Expand All @@ -218,8 +224,11 @@ public List<Trip> getTrips() {
*
* @param limit Maximum number of results.
* @return List of trips.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Trip> getTrips(final Integer limit) {
public List<Trip> getTrips(final Integer limit) throws UraClientException {
return getTrips(new Query(), limit);
}

Expand All @@ -229,8 +238,12 @@ public List<Trip> getTrips(final Integer limit) {
*
* @param query The query.
* @return List of trips.
* @throws UraClientException Error with API communication.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Trip> getTrips(final Query query) {
public List<Trip> getTrips(final Query query) throws UraClientException {
return getTrips(query, null);
}

Expand All @@ -240,8 +253,11 @@ public List<Trip> getTrips(final Query query) {
* @param query The query.
* @param limit Maximum number of results.
* @return List of trips.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Trip> getTrips(final Query query, final Integer limit) {
public List<Trip> getTrips(final Query query, final Integer limit) throws UraClientException {
List<Trip> trips = new ArrayList<>();
try (InputStream is = requestInstant(REQUEST_TRIP, query);
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
Expand All @@ -260,7 +276,7 @@ public List<Trip> getTrips(final Query query, final Integer limit) {
line = br.readLine();
}
} catch (IOException e) {
throw new IllegalStateException("Failed to read trips from API", e);
throw new UraClientException("Failed to read trips from API", e);
}
return trips;
}
Expand All @@ -271,11 +287,11 @@ public List<Trip> getTrips(final Query query, final Integer limit) {
* @param query The query.
* @param consumer Consumer(s) for single trips.
* @return Trip reader.
* @throws IOException Error reading response.
* @throws UraClientConfigurationException Error reading response.
* @see #getTripsStream(Query, List)
* @since 1.2.0
* @since 1.2
*/
public AsyncUraTripReader getTripsStream(final Query query, final Consumer<Trip> consumer) throws IOException {
public AsyncUraTripReader getTripsStream(final Query query, final Consumer<Trip> consumer) throws UraClientConfigurationException {
return getTripsStream(query, Collections.singletonList(consumer));
}

Expand All @@ -285,28 +301,36 @@ public AsyncUraTripReader getTripsStream(final Query query, final Consumer<Trip>
* @param query The query.
* @param consumers Consumer(s) for single trips.
* @return Trip reader.
* @throws IOException Error retrieving stream response.
* @since 1.2.0
* @throws UraClientConfigurationException Error retrieving stream response.
* @since 1.2
* @since 2.0 Throws {@link UraClientConfigurationException}.
*/
public AsyncUraTripReader getTripsStream(final Query query, final List<Consumer<Trip>> consumers) throws IOException {
public AsyncUraTripReader getTripsStream(final Query query, final List<Consumer<Trip>> consumers) throws UraClientConfigurationException {
// Create the reader.
AsyncUraTripReader reader = new AsyncUraTripReader(
new URL(requestURL(config.getBaseURL() + config.getStreeamPath(), REQUEST_TRIP, query)),
consumers
);
try {
AsyncUraTripReader reader = new AsyncUraTripReader(
new URL(requestURL(config.getBaseURL() + config.getStreeamPath(), REQUEST_TRIP, query)),
consumers
);

// Open the reader, i.e. start reading from API.
reader.open();
// Open the reader, i.e. start reading from API.
reader.open();

return reader;
return reader;
} catch (MalformedURLException e) {
throw new UraClientConfigurationException("Invalid API URL, check client configuration.", e);
}
}

/**
* Get list of stops without filters.
*
* @return The list of stops.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Stop> getStops() {
public List<Stop> getStops() throws UraClientException {
return getStops(new Query());
}

Expand All @@ -316,8 +340,11 @@ public List<Stop> getStops() {
*
* @param query The query.
* @return The list.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Stop> getStops(final Query query) {
public List<Stop> getStops(final Query query) throws UraClientException {
List<Stop> stops = new ArrayList<>();
try (InputStream is = requestInstant(REQUEST_STOP, query);
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
Expand All @@ -330,7 +357,7 @@ public List<Stop> getStops(final Query query) {
}
}
} catch (IOException e) {
throw new IllegalStateException("Failed to read stops from API", e);
throw new UraClientException("Failed to read stops from API", e);
}
return stops;
}
Expand All @@ -339,9 +366,11 @@ public List<Stop> getStops(final Query query) {
* Get list of messages.
*
* @return List of messages.
* @throws UraClientException Error with API communication.
* @since 1.3
* @since 2.0 Throw {@link UraClientException}.
*/
public List<Message> getMessages() {
public List<Message> getMessages() throws UraClientException {
return getMessages(new Query(), null);
}

Expand All @@ -352,9 +381,11 @@ public List<Message> getMessages() {
*
* @param query The query.
* @return List of trips.
* @throws UraClientException Error with API communication.
* @since 1.3
* @since 2.0 Throw {@link UraClientException}.
*/
public List<Message> getMessages(final Query query) {
public List<Message> getMessages(final Query query) throws UraClientException {
return getMessages(query, null);
}

Expand All @@ -364,9 +395,11 @@ public List<Message> getMessages(final Query query) {
* @param query The query.
* @param limit Maximum number of results.
* @return List of trips.
* @throws UraClientException Error with API communication.
* @since 1.3
* @since 2.0 Throw {@link UraClientException}.
*/
public List<Message> getMessages(final Query query, final Integer limit) {
public List<Message> getMessages(final Query query, final Integer limit) throws UraClientException {
List<Message> messages = new ArrayList<>();
try (InputStream is = requestInstant(REQUEST_MESSAGE, query);
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
Expand All @@ -385,7 +418,7 @@ public List<Message> getMessages(final Query query, final Integer limit) {
line = br.readLine();
}
} catch (IOException e) {
throw new IllegalStateException("Failed to read messages from API", e);
throw new UraClientException("Failed to read messages from API", e);
}
return messages;
}
Expand All @@ -409,35 +442,35 @@ private InputStream requestInstant(final String[] returnList, final Query query)
* @param returnList Fields to fetch.
* @param query The query.
* @return The URL
* @throws IOException on errors
* @since 1.2.0
* @since 1.2
* @since 2.0 Does not throw exception anymore.
*/
private String requestURL(final String endpointURL, final String[] returnList, final Query query) throws IOException {
private String requestURL(final String endpointURL, final String[] returnList, final Query query) {
String urlStr = endpointURL + "?ReturnList=" + String.join(",", returnList);

if (query.stopIDs != null && query.stopIDs.length > 0) {
urlStr += "&" + PAR_STOP_ID + "=" + URLEncoder.encode(String.join(",", query.stopIDs), UTF_8.name());
urlStr += "&" + PAR_STOP_ID + "=" + URLEncoder.encode(String.join(",", query.stopIDs), UTF_8);
}
if (query.stopNames != null && query.stopNames.length > 0) {
urlStr += "&" + PAR_STOP_NAME + "=" + URLEncoder.encode(String.join(",", query.stopNames), UTF_8.name());
urlStr += "&" + PAR_STOP_NAME + "=" + URLEncoder.encode(String.join(",", query.stopNames), UTF_8);
}
if (query.lineIDs != null && query.lineIDs.length > 0) {
urlStr += "&" + PAR_LINE_ID + "=" + URLEncoder.encode(String.join(",", query.lineIDs), UTF_8.name());
urlStr += "&" + PAR_LINE_ID + "=" + URLEncoder.encode(String.join(",", query.lineIDs), UTF_8);
}
if (query.lineNames != null && query.lineNames.length > 0) {
urlStr += "&" + PAR_LINE_NAME + "=" + URLEncoder.encode(String.join(",", query.lineNames), UTF_8.name());
urlStr += "&" + PAR_LINE_NAME + "=" + URLEncoder.encode(String.join(",", query.lineNames), UTF_8);
}
if (query.direction != null) {
urlStr += "&" + PAR_DIR_ID + "=" + query.direction;
}
if (query.destinationNames != null) {
urlStr += "&" + PAR_DEST_NAME + "=" + URLEncoder.encode(String.join(",", query.destinationNames), UTF_8.name());
urlStr += "&" + PAR_DEST_NAME + "=" + URLEncoder.encode(String.join(",", query.destinationNames), UTF_8);
}
if (query.towards != null) {
urlStr += "&" + PAR_TOWARDS + "=" + URLEncoder.encode(String.join(",", query.towards), UTF_8.name());
urlStr += "&" + PAR_TOWARDS + "=" + URLEncoder.encode(String.join(",", query.towards), UTF_8);
}
if (query.circle != null) {
urlStr += "&" + PAR_CIRCLE + "=" + URLEncoder.encode(query.circle, UTF_8.name());
urlStr += "&" + PAR_CIRCLE + "=" + URLEncoder.encode(query.circle, UTF_8);
}

return urlStr;
Expand Down Expand Up @@ -572,17 +605,23 @@ public Query forPosition(final Double latitude, final Double longitude, final In
* Get stops for set filters.
*
* @return List of matching trips.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Stop> getStops() {
public List<Stop> getStops() throws UraClientException {
return UraClient.this.getStops(this);
}

/**
* Get trips for set filters.
*
* @return List of matching trips.
* @throws UraClientException Error with API communication.
* @since 1.0
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Trip> getTrips() {
public List<Trip> getTrips() throws UraClientException {
return UraClient.this.getTrips(this);
}

Expand All @@ -591,11 +630,11 @@ public List<Trip> getTrips() {
*
* @param consumer Consumer for single trips.
* @return Trip reader.
* @throws IOException Errors retrieving stream response.
* @throws UraClientConfigurationException Error reading response.
* @see #getTripsStream(List)
* @since 1.2.0
* @since 1.2
*/
public AsyncUraTripReader getTripsStream(Consumer<Trip> consumer) throws IOException {
public AsyncUraTripReader getTripsStream(Consumer<Trip> consumer) throws UraClientConfigurationException {
return UraClient.this.getTripsStream(this, consumer);
}

Expand All @@ -604,20 +643,22 @@ public AsyncUraTripReader getTripsStream(Consumer<Trip> consumer) throws IOExcep
*
* @param consumers Consumers for single trips.
* @return Trip reader.
* @throws IOException Errors retrieving stream response.
* @since 1.2.0
* @throws UraClientConfigurationException Errors retrieving stream response.
* @since 1.2
*/
public AsyncUraTripReader getTripsStream(List<Consumer<Trip>> consumers) throws IOException {
public AsyncUraTripReader getTripsStream(List<Consumer<Trip>> consumers) throws UraClientConfigurationException {
return UraClient.this.getTripsStream(this, consumers);
}

/**
* Get trips for set filters.
*
* @return List of matching messages.
* @throws UraClientException Error with API communication.
* @since 1.3
* @since 2.0 Throws {@link UraClientException}.
*/
public List<Message> getMessages() {
public List<Message> getMessages() throws UraClientException {
return UraClient.this.getMessages(this);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2016-2020 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.stklcode.pubtrans.ura.exception;

/**
* Custom exception class indicating an error with the URA client configuration.
*
* @author Stefan Kalscheuer
* @since 2.0
*/
public class UraClientConfigurationException extends UraClientException {
private static final long serialVersionUID = -8035752391477338659L;

/**
* Default constructor.
*
* @param message The detail message (which is saved for later retrieval by the {@link #getMessage()} method)
* @param cause The cause (which is saved for later retrieval by the {@link #getCause()} method).
*/
public UraClientConfigurationException(String message, Throwable cause) {
super(message, cause);
}
}
Loading

0 comments on commit 1148734

Please sign in to comment.