Skip to content

Commit

Permalink
Merge pull request #30 from Bandwidth/SWI-6678
Browse files Browse the repository at this point in the history
SWI-6678
  • Loading branch information
ajrice6713 authored Dec 4, 2024
2 parents 383ccb5 + fb50030 commit 783c420
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 4 deletions.
9 changes: 9 additions & 0 deletions src/main/java/com/bandwidth/sdk/numbers/NumbersClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.bandwidth.sdk.numbers.models.orders.Order;
import com.bandwidth.sdk.numbers.models.orders.OrderResponse;
import com.bandwidth.sdk.numbers.models.AvailableNumberSearchRequest;
import com.bandwidth.sdk.numbers.models.orders.OrdersResponse;

public interface NumbersClient extends AutoCloseable {

Expand Down Expand Up @@ -34,4 +35,12 @@ public interface NumbersClient extends AutoCloseable {
* @return {@link OrderResponse} with the details of the results of placing the order
*/
OrderResponse getOrderStatus(String orderId);

/**
* Fetch the details of all orders.
*
* @param customerOrderId The customerOrderId of the order to search on
* @return {@link OrdersResponse} with the details of all orders
*/
OrdersResponse getOrdersByCustomerOrderId(String customerOrderId);
}
37 changes: 37 additions & 0 deletions src/main/java/com/bandwidth/sdk/numbers/NumbersClientImpl.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.bandwidth.sdk.numbers;

import com.bandwidth.sdk.numbers.exception.ExceptionUtils;
import com.bandwidth.sdk.numbers.exception.NumbersApiException;
import com.bandwidth.sdk.numbers.helpers.RetryableRequest;
import com.bandwidth.sdk.numbers.helpers.SleepRetryPolicy;
import com.bandwidth.sdk.numbers.models.AvailableNumberSearchRequest;
import com.bandwidth.sdk.numbers.models.SearchResult;
import com.bandwidth.sdk.numbers.models.orders.Order;
import com.bandwidth.sdk.numbers.models.orders.OrderResponse;
import com.bandwidth.sdk.numbers.models.orders.OrdersResponse;
import com.bandwidth.sdk.numbers.serde.NumbersSerde;
import com.google.common.base.Preconditions;
import io.netty.handler.codec.http.HttpHeaderNames;
Expand Down Expand Up @@ -105,6 +107,41 @@ public OrderResponse getOrderStatus(String orderId) {
});
}

/**
* This queries the /orders API with a required parameter of customerOrderId
* If we need to extend this for any reason, we should implement a getOrders method with a builder for the possible query parameters
* The HTTP client will need to be investigated to see how it will support adding multiple query parameters
*
* @param customerOrderId The customerOrderId of the order to search on
* @return The orders response
*/
@Override
public OrdersResponse getOrdersByCustomerOrderId(String customerOrderId){
return getOrdersByCustomerOrderIdAsync(customerOrderId).join();
}

private CompletableFuture<OrdersResponse> getOrdersByCustomerOrderIdAsync(String customerOrderId) throws NumbersApiException {
// arbitrary
String pageSize = "100";

return catchAsyncClientExceptions(() -> {
String url = MessageFormat.format("{0}/accounts/{1}/orders?customerOrderId={2}&page=1&size={3}", baseUrl, account, customerOrderId, pageSize);
return httpClient.prepareGet(url)
.execute()
.toCompletableFuture()
.thenApply(resp -> {
String responseBodyString = resp.getResponseBody(StandardCharsets.UTF_8);
if (resp.getStatusCode() != 200) {
if (resp.getStatusCode() == 204) {
throw new NumbersApiException("No orders found");
}
throw new NumbersApiException("Error fetching orders. Response body: " + responseBodyString + "; Status code: " + resp.getStatusCode());
}
return NumbersSerde.deserialize(responseBodyString, OrdersResponse.class);
});
});
}

@Override
public void close() {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.bandwidth.sdk.numbers.models.orders;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import org.immutables.value.Value;

import javax.annotation.Nullable;

@Value.Immutable
@JsonSerialize(as = ImmutableOrdersResponse.class)
@JsonDeserialize(as = ImmutableOrdersResponse.class)
@JacksonXmlRootElement(localName = "ResponseSelectWrapper")
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class OrdersResponse {
@Value.Redacted
@Nullable
@JacksonXmlProperty(localName = "ListOrderIdUserIdDate")
public abstract OrdersResponseWrapper getOrdersResponseData();

public static ImmutableOrdersResponse.Builder builder() {
return ImmutableOrdersResponse.builder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.bandwidth.sdk.numbers.models.orders;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import org.immutables.value.Value;

import javax.annotation.Nullable;
import java.util.Date;

@Value.Immutable
@JsonSerialize(as = ImmutableOrdersResponseData.class)
@JsonDeserialize(as = ImmutableOrdersResponseData.class)
@JacksonXmlRootElement(localName = "OrderIdUserIdDate")
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class OrdersResponseData {
@Nullable
@JacksonXmlProperty(localName = "accountId")
public abstract String getAccountId();

@Nullable
@JacksonXmlProperty(localName = "CountOfTNs")
public abstract Integer getCountOfTns();

@Nullable
@JacksonXmlProperty(localName = "CustomerOrderId")
public abstract String getCustomerOrderId();

@Nullable
@JacksonXmlProperty(localName = "userId")
public abstract String getUserId();

@Nullable
@JacksonXmlProperty(localName = "lastModifiedDate")
public abstract Date getLastModifiedDate();

@Nullable
@JacksonXmlProperty(localName = "OrderDate")
public abstract Date getOrderDate();

@Nullable
@JacksonXmlProperty(localName = "OrderType")
public abstract String getOrderType();

@Nullable
@JacksonXmlProperty(localName = "orderId")
public abstract String getOrderId();

@Nullable
@JacksonXmlProperty(localName = "OrderStatus")
public abstract OrderResponse.OrderStatus getOrderStatus();

@Nullable
@JacksonXmlProperty(localName = "Summary")
public abstract String getSummary();

public static ImmutableOrdersResponseData.Builder builder() {
return ImmutableOrdersResponseData.builder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.bandwidth.sdk.numbers.models.orders;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import org.immutables.value.Value;

import javax.annotation.Nullable;

@Value.Immutable
@JsonSerialize(as = ImmutableOrdersResponseLinks.class)
@JsonDeserialize(as = ImmutableOrdersResponseLinks.class)
@JacksonXmlRootElement(localName = "Links")
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class OrdersResponseLinks {
@Nullable
@JacksonXmlProperty(localName = "first")
public abstract String getFirst();

@Nullable
@JacksonXmlProperty(localName = "next")
public abstract String getNext();

public static ImmutableOrdersResponseLinks.Builder builder() {
return ImmutableOrdersResponseLinks.builder();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.bandwidth.sdk.numbers.models.orders;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import org.immutables.value.Value;

import javax.annotation.Nullable;
import java.util.List;

@Value.Immutable
@JsonSerialize(as = ImmutableOrdersResponseWrapper.class)
@JsonDeserialize(as = ImmutableOrdersResponseWrapper.class)
@JacksonXmlRootElement(localName = "ListOrderIdUserIdDate")
@JsonIgnoreProperties(ignoreUnknown = true)
public abstract class OrdersResponseWrapper {
@Nullable
@JacksonXmlProperty(localName = "TotalCount")
public abstract Integer getTotalCount();

@Nullable
@JacksonXmlElementWrapper(localName = "Links")
public abstract OrdersResponseLinks getLinks();

@Nullable
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "OrderIdUserIdDate")
public abstract List<OrdersResponseData> getOrders();

public static ImmutableOrdersResponseWrapper.Builder builder() {
return ImmutableOrdersResponseWrapper.builder();
}
}
62 changes: 58 additions & 4 deletions src/test/java/com/bandwidth/sdk/numbers/NumbersClientImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
import com.bandwidth.sdk.numbers.models.ImmutableErrorResponse;
import com.bandwidth.sdk.numbers.models.ImmutableSearchResult;
import com.bandwidth.sdk.numbers.models.SearchResult;
import com.bandwidth.sdk.numbers.models.orders.ExistingTelephoneNumberOrderType;
import com.bandwidth.sdk.numbers.models.orders.ImmutableOrderResponse;
import com.bandwidth.sdk.numbers.models.orders.Order;
import com.bandwidth.sdk.numbers.models.orders.OrderResponse;
import com.bandwidth.sdk.numbers.models.orders.*;
import com.bandwidth.sdk.numbers.serde.NumbersSerde;
import org.assertj.core.api.Assertions;
import org.asynchttpclient.AsyncHttpClient;
Expand All @@ -23,6 +20,7 @@
import org.mockito.junit.MockitoJUnitRunner;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

Expand Down Expand Up @@ -80,6 +78,23 @@ public class NumbersClientImplTest {
.order(order)
.build();

private final OrdersResponse ordersResponse = ImmutableOrdersResponse.builder()
.ordersResponseData(OrdersResponseWrapper.builder()
.addOrders(ImmutableOrdersResponseData.builder()
.accountId("1")
.countOfTns(1)
.customerOrderId("foo")
.userId("1")
.lastModifiedDate(null)
.orderDate(null)
.orderType("1")
.orderId("1")
.orderStatus(OrderResponse.OrderStatus.COMPLETE)
.summary("1")
.build())
.build())
.build();

@Mock
private AsyncHttpClient asyncHttpClient;
@Mock
Expand Down Expand Up @@ -179,4 +194,43 @@ public void orderNumbersWithError() {
assertThat(thrown).isInstanceOf(NumbersApiException.class);
}

@Test
public void searchForNumberByCustomerOrderId() {
when(asyncHttpClient.prepareGet(anyString())).thenReturn(boundRequestBuilder);
when(boundRequestBuilder.execute()).thenReturn(listenableFuture);
when(listenableFuture.toCompletableFuture()).thenReturn(CompletableFuture.completedFuture(response));
when(response.getStatusCode()).thenReturn(200);
when(response.getResponseBody(StandardCharsets.UTF_8)).thenReturn(NumbersSerde.serialize(ordersResponse));

assertThat(ordersResponse).isEqualTo(numbersClient.getOrdersByCustomerOrderId("foo"));
List<OrdersResponseData> orders = ordersResponse.getOrdersResponseData().getOrders();
assertThat(orders).hasSize(1);
assertThat(orders.get(0).getCustomerOrderId()).isEqualTo("foo");
assertThat(orders.get(0).getOrderId()).isEqualTo("1");

verify(asyncHttpClient, times(1)).prepareGet(anyString());
}

@Test
public void searchForNumberByCustomerOrderIdNoOrdersFound() {
when(asyncHttpClient.prepareGet(anyString())).thenReturn(boundRequestBuilder);
when(boundRequestBuilder.execute()).thenReturn(listenableFuture);
when(listenableFuture.toCompletableFuture()).thenReturn(CompletableFuture.completedFuture(response));
when(response.getStatusCode()).thenReturn(204);

Throwable thrown = Assertions.catchThrowable(() -> numbersClient.getOrdersByCustomerOrderId("foo"));
assertThat(thrown).isInstanceOf(CompletionException.class).hasCauseInstanceOf(NumbersApiException.class);
}

@Test
public void searchForNumberByCustomerOrderIdRequestError() {
when(asyncHttpClient.prepareGet(anyString())).thenReturn(boundRequestBuilder);
when(boundRequestBuilder.execute()).thenReturn(listenableFuture);
when(listenableFuture.toCompletableFuture()).thenReturn(CompletableFuture.completedFuture(response));
when(response.getStatusCode()).thenReturn(400);

Throwable thrown = Assertions.catchThrowable(() -> numbersClient.getOrdersByCustomerOrderId("foo"));
assertThat(thrown).isInstanceOf(CompletionException.class).hasCauseInstanceOf(NumbersApiException.class);
}

}

0 comments on commit 783c420

Please sign in to comment.