Skip to content

Commit a9806a3

Browse files
author
Cameron Mace
authored
Added optimized trips rx (#443)
* added optimized trips rx * removed unused import * removed spacing issue * added sanity test to optimized trips rx
1 parent 3c636fd commit a9806a3

3 files changed

Lines changed: 245 additions & 0 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.mapbox.services.api.rx.optimizedtrips.v1;
2+
3+
import com.mapbox.services.api.ServicesException;
4+
import com.mapbox.services.api.optimizedtrips.v1.MapboxOptimizedTrips;
5+
import com.mapbox.services.api.optimizedtrips.v1.models.OptimizedTripsResponse;
6+
7+
import io.reactivex.Observable;
8+
import retrofit2.Retrofit;
9+
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
10+
import retrofit2.converter.gson.GsonConverterFactory;
11+
12+
/**
13+
* The Mapbox Optimized Trips API returns a duration-optimized trip between the input coordinates. This is also known
14+
* as solving the Traveling Salesperson Problem. A typical use case for this API is planning the route for deliveries
15+
* in a city. Optimized trips can be retrieved for car driving, bicycling and walking or hiking.
16+
* <p>
17+
* Under normal plans, a maximum of 12 coordinates can be passed in at once at a maximum 60 requests per minute. For
18+
* higher volumes, reach out through our contact page.
19+
* <p>
20+
* Note that for under 10 coordinates, the returned results will be optimal. For 10 and more coordinates, the results
21+
* will be optimized approximations.
22+
*
23+
* @see <a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem">Traveling Salesperson Problem</a>
24+
* @see <a href="https://www.mapbox.com/api-documentation/#optimized-trips">API documentation</a>
25+
* @since 2.1.0
26+
*/
27+
public class MapboxOptimizedTripsRx extends MapboxOptimizedTrips {
28+
29+
private OptimizedTripsServiceRx serviceRx = null;
30+
private Observable<OptimizedTripsResponse> observable = null;
31+
32+
public MapboxOptimizedTripsRx(Builder builder) {
33+
super(builder);
34+
}
35+
36+
private OptimizedTripsServiceRx getServiceRx() {
37+
// No need to recreate it
38+
if (serviceRx != null) {
39+
return serviceRx;
40+
}
41+
42+
// Retrofit instance
43+
Retrofit retrofit = new Retrofit.Builder()
44+
.client(getOkHttpClient())
45+
.baseUrl(builder.getBaseUrl())
46+
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
47+
.addConverterFactory(GsonConverterFactory.create())
48+
.build();
49+
50+
// Directions service
51+
serviceRx = retrofit.create(OptimizedTripsServiceRx.class);
52+
return serviceRx;
53+
}
54+
55+
public Observable<OptimizedTripsResponse> getObservable() {
56+
// No need to recreate it
57+
if (observable != null) {
58+
return observable;
59+
}
60+
61+
observable = getServiceRx().getObservable(
62+
getHeaderUserAgent(builder.getClientAppName()),
63+
builder.getUser(),
64+
builder.getProfile(),
65+
builder.getCoordinates(),
66+
builder.getAccessToken(),
67+
builder.getRoundTrip(),
68+
builder.getRadiuses(),
69+
builder.getBearings(),
70+
builder.getSteps(),
71+
builder.getOverview(),
72+
builder.getGeometries(),
73+
builder.getAnnotation(),
74+
builder.getDestination(),
75+
builder.getSource());
76+
77+
// Done
78+
return observable;
79+
}
80+
81+
public static class Builder extends MapboxOptimizedTrips.Builder<Builder> {
82+
@Override
83+
public MapboxOptimizedTripsRx build() throws ServicesException {
84+
super.build();
85+
return new MapboxOptimizedTripsRx(this);
86+
}
87+
}
88+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.mapbox.services.api.rx.optimizedtrips.v1;
2+
3+
import com.mapbox.services.api.optimizedtrips.v1.models.OptimizedTripsResponse;
4+
5+
import io.reactivex.Observable;
6+
import retrofit2.http.GET;
7+
import retrofit2.http.Header;
8+
import retrofit2.http.Path;
9+
import retrofit2.http.Query;
10+
11+
/**
12+
* Interface that defines the Optimized Trips service (v1).
13+
*
14+
* @since 2.1.0
15+
*/
16+
public interface OptimizedTripsServiceRx {
17+
18+
/**
19+
* @param userAgent The user.
20+
* @param user The user.
21+
* @param profile The profile directions should use.
22+
* @param coordinates The coordinates used to calculate the trip.
23+
* @param accessToken Mapbox access token.
24+
* @param roundTrip Returned route is a roundtrip (route returns to first location). Allowed values are: true
25+
* (default) or false.
26+
* @param radiuses Maximum distance in meters that each coordinate is allowed to move when snapped to a nearby
27+
* road segment. There must be as many radiuses as there are coordinates in the request. Values
28+
* can be any number greater than 0 or they can be the string unlimited. If no routable road is
29+
* found within the radius, a NoSegment error is returned.
30+
* @param bearings Used to filter the road segment the waypoint will be placed on by direction and dictates
31+
* the angle of approach
32+
* @param steps Define if you'd like the route steps.
33+
* @param geometries Route geometry.
34+
* @param annotations An annotations object that contains additional details about each line segment along the
35+
* route geometry. Each entry in an annotations field corresponds to a coordinate along the
36+
* route geometry.
37+
* @param destination Returned route ends at any or last coordinate. Allowed values are: any (default) or last.
38+
* @param source Returned route starts at any or first coordinate. Allowed values are: any (default) or first.
39+
* @since 2.1.0
40+
*/
41+
@GET("optimized-trips/v1/{user}/{profile}/{coordinates}")
42+
Observable<OptimizedTripsResponse> getObservable(
43+
@Header("User-Agent") String userAgent,
44+
@Path("user") String user,
45+
@Path("profile") String profile,
46+
@Path("coordinates") String coordinates,
47+
@Query("access_token") String accessToken,
48+
@Query("roundtrip") Boolean roundTrip,
49+
@Query("radiuses") double[] radiuses,
50+
@Query("bearings") double[][] bearings,
51+
@Query("steps") Boolean steps,
52+
@Query("overview") String overview,
53+
@Query("geometries") String geometries,
54+
@Query("annotations") String[] annotations,
55+
@Query("destination") String destination,
56+
@Query("source") String source
57+
);
58+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.mapbox.services.api.rx.optimizedtrips.v1;
2+
3+
import com.mapbox.services.api.ServicesException;
4+
import com.mapbox.services.api.directions.v5.DirectionsCriteria;
5+
import com.mapbox.services.api.optimizedtrips.v1.models.OptimizedTripsResponse;
6+
import com.mapbox.services.commons.models.Position;
7+
8+
import org.hamcrest.junit.ExpectedException;
9+
import org.junit.After;
10+
import org.junit.Before;
11+
import org.junit.Rule;
12+
import org.junit.Test;
13+
14+
import java.io.IOException;
15+
import java.nio.charset.Charset;
16+
import java.nio.file.Files;
17+
import java.nio.file.Paths;
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
21+
import io.reactivex.observers.TestObserver;
22+
import okhttp3.HttpUrl;
23+
import okhttp3.mockwebserver.Dispatcher;
24+
import okhttp3.mockwebserver.MockResponse;
25+
import okhttp3.mockwebserver.MockWebServer;
26+
import okhttp3.mockwebserver.RecordedRequest;
27+
28+
import static org.junit.Assert.assertEquals;
29+
30+
public class MapboxOptimizedTripsRxTest {
31+
32+
public static final String OPTIMIZED_TRIP_FIXTURE = "../libjava-services/src/test/fixtures/optimized_trip.json";
33+
34+
private static final String ACCESS_TOKEN = "pk.XXX";
35+
36+
private MockWebServer server;
37+
private HttpUrl mockUrl;
38+
39+
private List<Position> coordinates;
40+
41+
@Rule
42+
public ExpectedException thrown = ExpectedException.none();
43+
44+
@Before
45+
public void setUp() throws IOException {
46+
server = new MockWebServer();
47+
48+
server.setDispatcher(new Dispatcher() {
49+
50+
@Override
51+
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
52+
try {
53+
String body = new String(Files.readAllBytes(Paths.get(OPTIMIZED_TRIP_FIXTURE)), Charset.forName("utf-8"));
54+
return new MockResponse().setBody(body);
55+
} catch (IOException ioException) {
56+
throw new RuntimeException(ioException);
57+
}
58+
}
59+
});
60+
61+
server.start();
62+
mockUrl = server.url("");
63+
64+
coordinates = new ArrayList<>();
65+
coordinates.add(Position.fromCoordinates(13.418946862220764, 52.50055852688439));
66+
coordinates.add(Position.fromCoordinates(13.419011235237122, 52.50113000479732));
67+
coordinates.add(Position.fromCoordinates(13.419756889343262, 52.50171780290061));
68+
coordinates.add(Position.fromCoordinates(13.419885635375975, 52.50237416816131));
69+
coordinates.add(Position.fromCoordinates(13.420631289482117, 52.50294888790448));
70+
}
71+
72+
@After
73+
public void tearDown() throws IOException {
74+
server.shutdown();
75+
}
76+
77+
@Test
78+
public void testSanityRX() throws ServicesException {
79+
MapboxOptimizedTripsRx client = new MapboxOptimizedTripsRx.Builder()
80+
.setAccessToken(ACCESS_TOKEN)
81+
.setProfile(DirectionsCriteria.PROFILE_DRIVING)
82+
.setCoordinates(coordinates)
83+
.setBaseUrl(mockUrl.toString())
84+
.build();
85+
86+
TestObserver<OptimizedTripsResponse> testObserver = new TestObserver<>();
87+
client.getObservable().subscribe(testObserver);
88+
89+
testObserver.assertComplete();
90+
testObserver.assertNoErrors();
91+
testObserver.assertValueCount(1);
92+
93+
List<List<Object>> events = testObserver.getEvents();
94+
assertEquals(1, events.get(0).size());
95+
96+
OptimizedTripsResponse response = (OptimizedTripsResponse) events.get(0).get(0);
97+
assertEquals(response.getCode(), DirectionsCriteria.RESPONSE_OK);
98+
}
99+
}

0 commit comments

Comments
 (0)