() {});
+ return Optional.ofNullable(authResponse.getAccessToken());
+ } catch (Exception e) {
+ return Optional.empty();
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/auth/models/BearerAuthResponse.java b/client/src/main/com/sinch/sdk/auth/models/BearerAuthResponse.java
new file mode 100644
index 00000000..66c751e9
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/auth/models/BearerAuthResponse.java
@@ -0,0 +1,52 @@
+package com.sinch.sdk.auth.models;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class BearerAuthResponse {
+ @JsonProperty("access_token")
+ String accessToken;
+
+ @JsonProperty("expires_in")
+ Integer expiresIn;
+
+ @JsonProperty("scope")
+ String scope;
+
+ @JsonProperty("token_type")
+ String tokenType;
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ /** @return Integer Token period expiration in seconds */
+ public Integer getExpiresIn() {
+ return expiresIn;
+ }
+
+ public String getScope() {
+ return scope;
+ }
+
+ public String getTokenType() {
+ return tokenType;
+ }
+
+ @Override
+ public String toString() {
+ // do not log token value
+ return "BearerAuthResponse{"
+ + "accessToken='"
+ + "<...>"
+ + '\''
+ + ", expiresIn="
+ + expiresIn
+ + ", scope='"
+ + scope
+ + '\''
+ + ", tokenType='"
+ + tokenType
+ + '\''
+ + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/ActiveNumberService.java b/client/src/main/com/sinch/sdk/domains/numbers/ActiveNumberService.java
new file mode 100644
index 00000000..7622a8e5
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/ActiveNumberService.java
@@ -0,0 +1,55 @@
+package com.sinch.sdk.domains.numbers;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.numbers.models.ActiveNumber;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberListRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.ActiveNumberListResponse;
+
+/**
+ * Active Numbers Service
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Active-Number
+ * @since 1.0
+ */
+public interface ActiveNumberService {
+
+ /**
+ * Lists active numbers for a project
+ *
+ * @param parameters Filtering criteria
+ * @return List of active numbers
+ * @since 1.0
+ */
+ ActiveNumberListResponse list(ActiveNumberListRequestParameters parameters) throws ApiException;
+
+ /**
+ * Get active number information by phone number
+ *
+ * @param phoneNumber Phone number
+ * @return Active number information
+ * @since 1.0
+ */
+ ActiveNumber get(String phoneNumber) throws ApiException;
+
+ /**
+ * Release an active number from the project
+ *
+ * @param phoneNumber Phone number
+ * @return Released active number
+ * @since 1.0
+ */
+ ActiveNumber release(String phoneNumber) throws ApiException;
+
+ /**
+ * Update an active phone number
+ *
+ * @param phoneNumber Phone number
+ * @param parameters Parameters to be updated
+ * @return Updated active number
+ * @since 1.0
+ */
+ ActiveNumber update(String phoneNumber, ActiveNumberUpdateRequestParameters parameters)
+ throws ApiException;
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/AvailableNumberService.java b/client/src/main/com/sinch/sdk/domains/numbers/AvailableNumberService.java
new file mode 100644
index 00000000..63b628a8
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/AvailableNumberService.java
@@ -0,0 +1,77 @@
+package com.sinch.sdk.domains.numbers;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.numbers.models.ActiveNumber;
+import com.sinch.sdk.domains.numbers.models.AvailableNumber;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberListAllRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentAnyRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.AvailableNumberListResponse;
+
+/**
+ * Available Number Service
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Available-Number
+ * @since 1.0
+ */
+public interface AvailableNumberService {
+
+ /**
+ * Search for available phone numbers
+ *
+ * Search for available phone numbers that are available for you to activate. You can filter by
+ * any property on the available number resource.
+ *
+ *
When searching, indicate the capability of the number in the array as SMS and/or VOICE. To
+ * search for a number capable of both, list both SMS and VOICE.
+ *
+ * @param parameters Filtering criteria
+ * @return List of available numbers according to search criteria
+ * @since 1.0
+ */
+ AvailableNumberListResponse list(AvailableNumberListAllRequestParameters parameters)
+ throws ApiException;
+
+ /**
+ * Get available number information by phone number
+ *
+ * @param phoneNumber Phone number
+ * @return Available number information
+ * @since 1.0
+ */
+ AvailableNumber get(String phoneNumber) throws ApiException;
+
+ /**
+ * Activate a new phone number
+ *
+ *
Activate a phone number to use with SMS products, Voice products, or both.
+ *
+ *
You'll use smsConfiguration to setup your number for SMS and voiceConfiguration for Voice.
+ * To setup for both, add both objects. See the dropdown menu (just under language selection) for
+ * code samples.
+ *
+ *
Note: You cannot add both objects if you only need to configure one object. For example, if
+ * you only need to configure smsConfiguration for SMS messaging, do not add the
+ * voiceConfiguration object or it will result in an error.
+ *
+ * @param phoneNumber Number to be activated
+ * @param parameters Activation parameters
+ * @return Activated number
+ * @since 1.0
+ */
+ ActiveNumber rent(String phoneNumber, AvailableNumberRentRequestParameters parameters)
+ throws ApiException;
+
+ /**
+ * Rent any number that matches the criteria
+ *
+ *
Activates a phone number that matches the search criteria provided in the request. Currently
+ * the rentAny operation works only for US LOCAL numbers
+ *
+ * @param parameters Selection and activation parameters
+ * @return Activated number according to criteria
+ * @since 1.0
+ */
+ ActiveNumber rentAny(AvailableNumberRentAnyRequestParameters parameters) throws ApiException;
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/AvailableRegionService.java b/client/src/main/com/sinch/sdk/domains/numbers/AvailableRegionService.java
new file mode 100644
index 00000000..01cdde6c
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/AvailableRegionService.java
@@ -0,0 +1,24 @@
+package com.sinch.sdk.domains.numbers;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableRegionListAllRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.AvailableRegionListResponse;
+
+/**
+ * Available Region Service
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Available-Regions
+ */
+public interface AvailableRegionService {
+
+ /**
+ * List available regions
+ *
+ * @param parameters Filtering criteria
+ * @return List of available regions according to search criteria
+ * @since 1.0
+ */
+ AvailableRegionListResponse list(AvailableRegionListAllRequestParameters parameters)
+ throws ApiException;
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/CallbackConfigurationService.java b/client/src/main/com/sinch/sdk/domains/numbers/CallbackConfigurationService.java
new file mode 100644
index 00000000..78aeab9d
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/CallbackConfigurationService.java
@@ -0,0 +1,32 @@
+package com.sinch.sdk.domains.numbers;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.numbers.models.CallbackConfiguration;
+import com.sinch.sdk.domains.numbers.models.requests.CallbackConfigurationUpdateRequestParameters;
+
+/**
+ * Callback Configuration Service
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/callbacks-numbers/tag/Callback-Configuration/
+ */
+public interface CallbackConfigurationService {
+
+ /**
+ * Get callbacks configuration
+ *
+ * @return callbacks configuration for the project
+ * @since 1.0
+ */
+ CallbackConfiguration get() throws ApiException;
+
+ /**
+ * Update callbacks configuration
+ *
+ * @param parameters Parameters to be updated
+ * @return Updated callbacks configuration
+ * @since 1.0
+ */
+ CallbackConfiguration update(CallbackConfigurationUpdateRequestParameters parameters)
+ throws ApiException;
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/NumbersService.java b/client/src/main/com/sinch/sdk/domains/numbers/NumbersService.java
new file mode 100644
index 00000000..75a79884
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/NumbersService.java
@@ -0,0 +1,43 @@
+package com.sinch.sdk.domains.numbers;
+
+/**
+ * Numbers Service
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/
+ * @since 1.0
+ */
+public interface NumbersService {
+
+ /**
+ * Available Number Service instance
+ *
+ * @return service instance for project
+ * @since 1.0
+ */
+ AvailableNumberService available();
+
+ /**
+ * Available Region Service instance
+ *
+ * @return service instance for project
+ * @since 1.0
+ */
+ AvailableRegionService regions();
+
+ /**
+ * Active Number Service instance
+ *
+ * @return service instance for project
+ * @since 1.0
+ */
+ ActiveNumberService active();
+
+ /**
+ * Callbacks Configuraiton Service instance
+ *
+ * @return service instance for project
+ * @since 1.0
+ */
+ CallbackConfigurationService callback();
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/ActiveNumberService.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/ActiveNumberService.java
new file mode 100644
index 00000000..ee620631
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/ActiveNumberService.java
@@ -0,0 +1,115 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.core.http.HttpMapper;
+import com.sinch.sdk.core.models.pagination.Page;
+import com.sinch.sdk.core.models.pagination.PageToken;
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.Pair;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.ActiveNumberApi;
+import com.sinch.sdk.domains.numbers.adapters.converters.ActiveNumberDtoConverter;
+import com.sinch.sdk.domains.numbers.adapters.converters.ActiveNumberUpdateRequestParametersDtoConverter;
+import com.sinch.sdk.domains.numbers.models.ActiveNumber;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.SearchPattern;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumbersResponseDto;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberListRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.ActiveNumberListResponse;
+import com.sinch.sdk.models.Configuration;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class ActiveNumberService implements com.sinch.sdk.domains.numbers.ActiveNumberService {
+
+ private Configuration configuration;
+ private ActiveNumberApi api;
+
+ public ActiveNumberService() {}
+
+ public ActiveNumberService(Configuration configuration, HttpClient httpClient) {
+ this.configuration = configuration;
+ this.api = new ActiveNumberApi(httpClient, configuration.getNumbersServer(), new HttpMapper());
+ }
+
+ private ActiveNumberApi getApi() {
+ return this.api;
+ }
+
+ public ActiveNumberListResponse list(ActiveNumberListRequestParameters parameters)
+ throws ApiException {
+
+ String regionCode = parameters.getRegionCode();
+ NumberType type = parameters.getType();
+
+ Optional pattern = parameters.getNumberPattern();
+ String patternPattern = null;
+ SearchPattern searchPattern = null;
+ if (pattern.isPresent()) {
+ NumberPattern p = pattern.get();
+ patternPattern = p.getPattern();
+ searchPattern = p.getSearchPattern();
+ }
+
+ List capabilities = null;
+ if (parameters.getCapabilities().isPresent()) {
+ capabilities =
+ parameters.getCapabilities().get().stream()
+ .map(EnumDynamic::value)
+ .collect(Collectors.toList());
+ }
+
+ Integer pageSize = parameters.getPageSize().orElse(null);
+
+ String orderBy = null;
+ if (parameters.getOrderBy().isPresent()) {
+ orderBy = parameters.getOrderBy().get().value();
+ }
+
+ String pageToken = parameters.getPageToken().orElse(null);
+ ActiveNumbersResponseDto response =
+ getApi()
+ .numberServiceListActiveNumbers(
+ configuration.getProjectId(),
+ regionCode,
+ type.value(),
+ patternPattern,
+ null != searchPattern ? searchPattern.value() : null,
+ capabilities,
+ pageSize,
+ pageToken,
+ orderBy);
+ Pair, PageToken> content =
+ ActiveNumberDtoConverter.convert(response);
+ return new ActiveNumberListResponse(
+ this, new Page<>(parameters, content.getLeft(), content.getRight()));
+ }
+
+ public ActiveNumber get(String phoneNumber) throws ApiException {
+ ActiveNumberDto response =
+ getApi().numberServiceGetActiveNumber(configuration.getProjectId(), phoneNumber);
+ return ActiveNumberDtoConverter.convert(response);
+ }
+
+ public ActiveNumber release(String phoneNumber) throws ApiException {
+ ActiveNumberDto response =
+ getApi().numberServiceReleaseNumber(configuration.getProjectId(), phoneNumber);
+ return ActiveNumberDtoConverter.convert(response);
+ }
+
+ public ActiveNumber update(String phoneNumber, ActiveNumberUpdateRequestParameters parameters)
+ throws ApiException {
+ ActiveNumberDto response =
+ getApi()
+ .numberServiceUpdateActiveNumber(
+ configuration.getProjectId(),
+ phoneNumber,
+ ActiveNumberUpdateRequestParametersDtoConverter.convert(parameters));
+ return ActiveNumberDtoConverter.convert(response);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/AvailableNumberService.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/AvailableNumberService.java
new file mode 100644
index 00000000..c5662b6b
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/AvailableNumberService.java
@@ -0,0 +1,110 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.core.http.HttpMapper;
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.AvailableNumberApi;
+import com.sinch.sdk.domains.numbers.adapters.converters.ActiveNumberDtoConverter;
+import com.sinch.sdk.domains.numbers.adapters.converters.AvailableNumberDtoConverter;
+import com.sinch.sdk.domains.numbers.adapters.converters.AvailableRentAnyRequestParametersDtoConverter;
+import com.sinch.sdk.domains.numbers.adapters.converters.AvailableRentRequestParametersDtoConverter;
+import com.sinch.sdk.domains.numbers.models.*;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumbersResponseDto;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberListAllRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentAnyRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.AvailableNumberListResponse;
+import com.sinch.sdk.models.Configuration;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class AvailableNumberService
+ implements com.sinch.sdk.domains.numbers.AvailableNumberService {
+
+ private Configuration configuration;
+ private AvailableNumberApi api;
+
+ public AvailableNumberService() {}
+
+ public AvailableNumberService(Configuration configuration, HttpClient httpClient) {
+ this.configuration = configuration;
+ this.api =
+ new AvailableNumberApi(httpClient, configuration.getNumbersServer(), new HttpMapper());
+ }
+
+ private AvailableNumberApi getApi() {
+ return this.api;
+ }
+
+ public AvailableNumberListResponse list(AvailableNumberListAllRequestParameters parameters)
+ throws ApiException {
+ String regionCode = parameters.getRegionCode();
+ NumberType type = parameters.getType();
+
+ Optional pattern = parameters.getNumberPattern();
+ String patternPattern = null;
+ SearchPattern searchPattern = null;
+ if (pattern.isPresent()) {
+ NumberPattern p = pattern.get();
+ patternPattern = p.getPattern();
+ searchPattern = p.getSearchPattern();
+ }
+
+ List capabilities = null;
+ if (parameters.getCapabilities().isPresent()) {
+ capabilities =
+ parameters.getCapabilities().get().stream()
+ .map(EnumDynamic::value)
+ .collect(Collectors.toList());
+ }
+
+ Integer size = parameters.getSize().orElse(null);
+
+ AvailableNumbersResponseDto response =
+ getApi()
+ .numberServiceListAvailableNumbers(
+ configuration.getProjectId(),
+ regionCode,
+ type.value(),
+ patternPattern,
+ null != searchPattern ? searchPattern.value() : null,
+ capabilities,
+ size);
+ Collection entities = AvailableNumberDtoConverter.convert(response);
+
+ return new AvailableNumberListResponse(entities);
+ }
+
+ public AvailableNumber get(String phoneNumber) throws ApiException {
+ AvailableNumberDto response =
+ getApi().numberServiceGetAvailableNumber(configuration.getProjectId(), phoneNumber);
+ return AvailableNumberDtoConverter.convert(response);
+ }
+
+ public ActiveNumber rent(String phoneNumber, AvailableNumberRentRequestParameters parameters)
+ throws ApiException {
+ ActiveNumberDto response =
+ getApi()
+ .numberServiceRentNumber(
+ configuration.getProjectId(),
+ phoneNumber,
+ AvailableRentRequestParametersDtoConverter.convert(parameters));
+ return ActiveNumberDtoConverter.convert(response);
+ }
+
+ public ActiveNumber rentAny(AvailableNumberRentAnyRequestParameters parameters)
+ throws ApiException {
+
+ ActiveNumberDto response =
+ getApi()
+ .numberServiceRentAnyNumber(
+ configuration.getProjectId(),
+ AvailableRentAnyRequestParametersDtoConverter.convert(parameters));
+ return ActiveNumberDtoConverter.convert(response);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/AvailableRegionService.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/AvailableRegionService.java
new file mode 100644
index 00000000..77a6a988
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/AvailableRegionService.java
@@ -0,0 +1,47 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.core.http.HttpMapper;
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.AvailableRegionsApi;
+import com.sinch.sdk.domains.numbers.adapters.converters.AvailableRegionsDtoConverter;
+import com.sinch.sdk.domains.numbers.models.Region;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ListAvailableRegionsResponseDto;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableRegionListAllRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.AvailableRegionListResponse;
+import com.sinch.sdk.models.Configuration;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class AvailableRegionService
+ implements com.sinch.sdk.domains.numbers.AvailableRegionService {
+
+ private Configuration configuration;
+ private AvailableRegionsApi api;
+
+ public AvailableRegionService() {}
+
+ public AvailableRegionService(Configuration configuration, HttpClient httpClient) {
+ this.configuration = configuration;
+ this.api =
+ new AvailableRegionsApi(httpClient, configuration.getNumbersServer(), new HttpMapper());
+ }
+
+ public AvailableRegionListResponse list(AvailableRegionListAllRequestParameters parameters)
+ throws ApiException {
+
+ List types = null;
+ if (parameters.getTypes().isPresent()) {
+ types =
+ parameters.getTypes().get().stream().map(EnumDynamic::value).collect(Collectors.toList());
+ }
+
+ ListAvailableRegionsResponseDto response =
+ api.numberServiceListAvailableRegions(configuration.getProjectId(), types);
+ Collection entities = AvailableRegionsDtoConverter.convert(response);
+
+ return new AvailableRegionListResponse(entities);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/CallbackConfigurationService.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/CallbackConfigurationService.java
new file mode 100644
index 00000000..8d7542cf
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/CallbackConfigurationService.java
@@ -0,0 +1,49 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.core.http.HttpMapper;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.CallbackConfigurationApi;
+import com.sinch.sdk.domains.numbers.adapters.converters.CallbackConfigurationDtoConverter;
+import com.sinch.sdk.domains.numbers.adapters.converters.CallbackConfigurationUpdateRequestParametersDtoConverter;
+import com.sinch.sdk.domains.numbers.models.CallbackConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.CallbackConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.requests.CallbackConfigurationUpdateRequestParameters;
+import com.sinch.sdk.models.Configuration;
+
+public class CallbackConfigurationService
+ implements com.sinch.sdk.domains.numbers.CallbackConfigurationService {
+
+ private Configuration configuration;
+ private CallbackConfigurationApi api;
+
+ public CallbackConfigurationService() {}
+
+ public CallbackConfigurationService(Configuration configuration, HttpClient httpClient) {
+ this.configuration = configuration;
+ this.api =
+ new CallbackConfigurationApi(
+ httpClient, configuration.getNumbersServer(), new HttpMapper());
+ }
+
+ private CallbackConfigurationApi getApi() {
+ return this.api;
+ }
+
+ public CallbackConfiguration get() throws ApiException {
+ CallbackConfigurationDto response =
+ getApi().getCallbackConfiguration(configuration.getProjectId());
+ return CallbackConfigurationDtoConverter.convert(response);
+ }
+
+ public CallbackConfiguration update(CallbackConfigurationUpdateRequestParameters parameters)
+ throws ApiException {
+
+ CallbackConfigurationDto response =
+ getApi()
+ .updateCallbackConfiguration(
+ configuration.getProjectId(),
+ CallbackConfigurationUpdateRequestParametersDtoConverter.convert(parameters));
+ return CallbackConfigurationDtoConverter.convert(response);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/NumbersService.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/NumbersService.java
new file mode 100644
index 00000000..cee4cd15
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/NumbersService.java
@@ -0,0 +1,47 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.models.Configuration;
+
+public class NumbersService implements com.sinch.sdk.domains.numbers.NumbersService {
+
+ private final Configuration configuration;
+ private final HttpClient httpClient;
+ private AvailableNumberService available;
+ private ActiveNumberService active;
+ private AvailableRegionService regions;
+ private CallbackConfigurationService callback;
+
+ public NumbersService(Configuration configuration, HttpClient httpClient) {
+ this.configuration = configuration;
+ this.httpClient = httpClient;
+ }
+
+ public AvailableNumberService available() {
+ if (null == this.available) {
+ this.available = new AvailableNumberService(configuration, httpClient);
+ }
+ return this.available;
+ }
+
+ public AvailableRegionService regions() {
+ if (null == this.regions) {
+ this.regions = new AvailableRegionService(configuration, httpClient);
+ }
+ return this.regions;
+ }
+
+ public ActiveNumberService active() {
+ if (null == this.active) {
+ this.active = new ActiveNumberService(configuration, httpClient);
+ }
+ return this.active;
+ }
+
+ public CallbackConfigurationService callback() {
+ if (null == this.callback) {
+ this.callback = new CallbackConfigurationService(configuration, httpClient);
+ }
+ return this.callback;
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberDtoConverter.java
new file mode 100644
index 00000000..a2b0104d
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberDtoConverter.java
@@ -0,0 +1,48 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.core.models.pagination.PageToken;
+import com.sinch.sdk.core.utils.Pair;
+import com.sinch.sdk.domains.numbers.models.ActiveNumber;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumbersResponseDto;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ActiveNumberDtoConverter {
+
+ public static Pair, PageToken> convert(
+ ActiveNumbersResponseDto dto) {
+ String nextPageToken = dto.getNextPageToken();
+ List list = dto.getActiveNumbers();
+ Collection pageContent = Collections.emptyList();
+ if (null != list) {
+ pageContent =
+ list.stream().map(ActiveNumberDtoConverter::convert).collect(Collectors.toList());
+ }
+ return new Pair<>(pageContent, new PageToken<>(nextPageToken));
+ }
+
+ public static ActiveNumber convert(ActiveNumberDto dto) {
+
+ return new ActiveNumber(
+ dto.getPhoneNumber(),
+ dto.getProjectId(),
+ dto.getDisplayName(),
+ dto.getRegionCode(),
+ NumberType.from(dto.getType()),
+ null != dto.getCapability()
+ ? dto.getCapability().stream().map(Capability::from).collect(Collectors.toList())
+ : null,
+ MoneyDtoConverter.convert(dto.getMoney()),
+ dto.getPaymentIntervalMonths(),
+ dto.getNextChargeDate().toInstant(),
+ null != dto.getExpireAt() ? dto.getExpireAt().toInstant() : null,
+ SmsConfigurationDtoConverter.convert(dto.getSmsConfiguration()),
+ VoiceConfigurationDtoConverter.convert(dto.getVoiceConfiguration()),
+ dto.getCallbackUrl());
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberUpdateRequestParametersDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberUpdateRequestParametersDtoConverter.java
new file mode 100644
index 00000000..8cca6abb
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberUpdateRequestParametersDtoConverter.java
@@ -0,0 +1,23 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberRequestDto;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateRequestParameters;
+
+public class ActiveNumberUpdateRequestParametersDtoConverter {
+
+ public static ActiveNumberRequestDto convert(ActiveNumberUpdateRequestParameters parameters) {
+ ActiveNumberRequestDto dto = new ActiveNumberRequestDto();
+ parameters.getDisplayName().ifPresent(dto::setDisplayName);
+ parameters
+ .getSmsConfiguration()
+ .ifPresent(value -> dto.setSmsConfiguration(SmsConfigurationDtoConverter.convert(value)));
+ parameters
+ .getVoiceConfiguration()
+ .ifPresent(
+ value -> dto.setVoiceConfiguration(VoiceConfigurationDtoConverter.convert(value)));
+ // TODO: OAS file do not yet contains callback field
+ // parameters.getCallback()
+ // .ifPresent(value -> dto.setCallback.convert(value)));
+ return dto;
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableNumberDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableNumberDtoConverter.java
new file mode 100644
index 00000000..bc144aad
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableNumberDtoConverter.java
@@ -0,0 +1,37 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.AvailableNumber;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumbersResponseDto;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class AvailableNumberDtoConverter {
+
+ public static Collection convert(AvailableNumbersResponseDto dto) {
+ List list = dto.getAvailableNumbers();
+ if (null == list) {
+ return Collections.emptyList();
+ }
+ return list.stream().map(AvailableNumberDtoConverter::convert).collect(Collectors.toList());
+ }
+
+ public static AvailableNumber convert(AvailableNumberDto dto) {
+
+ return new AvailableNumber(
+ dto.getPhoneNumber(),
+ dto.getRegionCode(),
+ NumberType.from(dto.getType()),
+ null != dto.getCapability()
+ ? dto.getCapability().stream().map(Capability::from).collect(Collectors.toList())
+ : null,
+ MoneyDtoConverter.convert(dto.getSetupPrice()),
+ MoneyDtoConverter.convert(dto.getMonthlyPrice()),
+ dto.getPaymentIntervalMonths(),
+ dto.getSupportingDocumentationRequired());
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRegionsDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRegionsDtoConverter.java
new file mode 100644
index 00000000..bb6eb1a6
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRegionsDtoConverter.java
@@ -0,0 +1,33 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.Region;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableRegionDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ListAvailableRegionsResponseDto;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class AvailableRegionsDtoConverter {
+
+ public static Collection convert(ListAvailableRegionsResponseDto dto) {
+ List list = dto.getAvailableRegions();
+ if (null == list) {
+ return Collections.emptyList();
+ }
+ return list.stream().map(AvailableRegionsDtoConverter::convert).collect(Collectors.toList());
+ }
+
+ public static Region convert(AvailableRegionDto dto) {
+
+ return Region.builder()
+ .setRegionCode(dto.getRegionCode())
+ .setRegionName(dto.getRegionName())
+ .setTypes(
+ null != dto.getTypes()
+ ? dto.getTypes().stream().map(NumberType::from).collect(Collectors.toList())
+ : null)
+ .build();
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentAnyRequestParametersDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentAnyRequestParametersDtoConverter.java
new file mode 100644
index 00000000..a1b88089
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentAnyRequestParametersDtoConverter.java
@@ -0,0 +1,58 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentAnyNumberRequestDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentAnyNumberRequestSmsConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentAnyNumberRequestVoiceConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.SearchPatternDto;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentAnyRequestParameters;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class AvailableRentAnyRequestParametersDtoConverter {
+ public static RentAnyNumberRequestDto convert(
+ AvailableNumberRentAnyRequestParameters parameters) {
+
+ RentAnyNumberRequestDto dto =
+ new RentAnyNumberRequestDto()
+ .regionCode(parameters.getRegionCode())
+ .type(parameters.getType().value());
+
+ Optional pattern = parameters.getNumberPattern();
+ if (pattern.isPresent()) {
+ NumberPattern p = pattern.get();
+ String patternPattern = p.getPattern();
+ String searchPattern = p.getSearchPattern().value();
+ SearchPatternDto spDto = new SearchPatternDto();
+ spDto.pattern(patternPattern);
+ spDto.searchPattern(searchPattern);
+ dto.numberPattern(spDto);
+ }
+
+ parameters
+ .getCapabilities()
+ .ifPresent(
+ value ->
+ dto.capabilities(
+ value.stream().map(EnumDynamic::value).collect(Collectors.toList())));
+
+ parameters
+ .getSmsConfiguration()
+ .ifPresent(
+ value ->
+ dto.smsConfiguration(
+ new RentAnyNumberRequestSmsConfigurationDto()
+ .campaignId(value.getCampaignId().orElse(null))
+ .servicePlanId(value.getServicePlanId())));
+ parameters
+ .getVoiceConfiguration()
+ .ifPresent(
+ value ->
+ dto.voiceConfiguration(
+ new RentAnyNumberRequestVoiceConfigurationDto().appId(value.getAppId())));
+
+ parameters.getCallBackUrl().ifPresent(dto::callbackUrl);
+ return dto;
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentRequestParametersDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentRequestParametersDtoConverter.java
new file mode 100644
index 00000000..a8e60b43
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentRequestParametersDtoConverter.java
@@ -0,0 +1,34 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentAnyNumberRequestSmsConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentAnyNumberRequestVoiceConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentNumberRequestDto;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.RentSMSConfigurationRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.RentVoiceConfigurationRequestParameters;
+import java.util.Optional;
+
+public class AvailableRentRequestParametersDtoConverter {
+
+ public static RentNumberRequestDto convert(AvailableNumberRentRequestParameters parameters) {
+
+ Optional sms = parameters.getSmsConfiguration();
+ Optional voice = parameters.getVoiceConfiguration();
+ Optional callbackUrl = parameters.getCallBackUrl();
+
+ RentNumberRequestDto dto = new RentNumberRequestDto();
+
+ sms.ifPresent(
+ value ->
+ dto.smsConfiguration(
+ new RentAnyNumberRequestSmsConfigurationDto()
+ .campaignId(value.getCampaignId().orElse(null))
+ .servicePlanId(value.getServicePlanId())));
+ voice.ifPresent(
+ value ->
+ dto.voiceConfiguration(
+ new RentAnyNumberRequestVoiceConfigurationDto().appId(value.getAppId())));
+ callbackUrl.ifPresent(dto::callbackUrl);
+ return dto;
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationDtoConverter.java
new file mode 100644
index 00000000..aed57be6
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationDtoConverter.java
@@ -0,0 +1,18 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.CallbackConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.CallbackConfigurationDto;
+
+public class CallbackConfigurationDtoConverter {
+
+ public static CallbackConfiguration convert(CallbackConfigurationDto dto) {
+
+ if (null == dto) {
+ return null;
+ }
+ return CallbackConfiguration.builder()
+ .setProjectId(dto.getProjectId())
+ .setHMACSecret(dto.getHmacSecret())
+ .build();
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationUpdateRequestParametersDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationUpdateRequestParametersDtoConverter.java
new file mode 100644
index 00000000..e2ec6c41
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationUpdateRequestParametersDtoConverter.java
@@ -0,0 +1,16 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.dto.v1.CallbackConfigurationUpdateDto;
+import com.sinch.sdk.domains.numbers.models.requests.CallbackConfigurationUpdateRequestParameters;
+
+public class CallbackConfigurationUpdateRequestParametersDtoConverter {
+
+ public static CallbackConfigurationUpdateDto convert(
+ CallbackConfigurationUpdateRequestParameters parameters) {
+
+ if (null == parameters) {
+ return null;
+ }
+ return new CallbackConfigurationUpdateDto().hmacSecret(parameters.getHMACSecret());
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/MoneyDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/MoneyDtoConverter.java
new file mode 100644
index 00000000..c6681dc4
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/MoneyDtoConverter.java
@@ -0,0 +1,15 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.Money;
+import com.sinch.sdk.domains.numbers.models.dto.v1.MoneyDto;
+
+public class MoneyDtoConverter {
+
+ public static Money convert(MoneyDto dto) {
+
+ if (null == dto) {
+ return null;
+ }
+ return new Money(dto.getCurrencyCode(), Double.valueOf(dto.getAmount()));
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledSmsProvisioningDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledSmsProvisioningDtoConverter.java
new file mode 100644
index 00000000..b389a964
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledSmsProvisioningDtoConverter.java
@@ -0,0 +1,42 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.ProvisioningStatus;
+import com.sinch.sdk.domains.numbers.models.ScheduledSmsProvisioning;
+import com.sinch.sdk.domains.numbers.models.SmsErrorCode;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ScheduledProvisioningDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.SmsErrorCodeDto;
+import java.time.ZoneOffset;
+import java.util.stream.Collectors;
+
+public class ScheduledSmsProvisioningDtoConverter {
+
+ public static ScheduledSmsProvisioning convert(ScheduledProvisioningDto dto) {
+
+ if (null == dto) {
+ return null;
+ }
+ return new ScheduledSmsProvisioning(
+ dto.getServicePlanId(),
+ dto.getCampaignId(),
+ ProvisioningStatus.from(dto.getStatus().getValue()),
+ dto.getLastUpdatedTime().toInstant(),
+ dto.getErrorCodes().stream()
+ .map(e -> SmsErrorCode.from(e.getValue()))
+ .collect(Collectors.toList()));
+ }
+
+ public static ScheduledProvisioningDto convert(ScheduledSmsProvisioning provisioning) {
+
+ if (null == provisioning) {
+ return null;
+ }
+
+ return new ScheduledProvisioningDto(
+ provisioning.getServicePlanId(),
+ provisioning.getCampaignId(),
+ provisioning.getLastUpdatedTime().atOffset(ZoneOffset.UTC),
+ provisioning.getErrorCodes().stream()
+ .map(e -> SmsErrorCodeDto.fromValue(e.value()))
+ .collect(Collectors.toList()));
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledVoiceProvisioningDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledVoiceProvisioningDtoConverter.java
new file mode 100644
index 00000000..c3fd3c3a
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledVoiceProvisioningDtoConverter.java
@@ -0,0 +1,34 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.ProvisioningStatus;
+import com.sinch.sdk.domains.numbers.models.ScheduledVoiceProvisioning;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ProvisioningStatusDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ScheduledVoiceProvisioningDto;
+import java.time.ZoneOffset;
+
+public class ScheduledVoiceProvisioningDtoConverter {
+
+ public static ScheduledVoiceProvisioning convert(ScheduledVoiceProvisioningDto dto) {
+
+ if (null == dto) {
+ return null;
+ }
+ return new ScheduledVoiceProvisioning(
+ dto.getAppId(),
+ ProvisioningStatus.from(dto.getStatus().getValue()),
+ dto.getLastUpdatedTime().toInstant());
+ }
+
+ public static ScheduledVoiceProvisioningDto convert(ScheduledVoiceProvisioning provisioning) {
+
+ if (null == provisioning) {
+ return null;
+ }
+
+ ScheduledVoiceProvisioningDto dto =
+ new ScheduledVoiceProvisioningDto(
+ provisioning.getAppId(), provisioning.getLastUpdatedTime().atOffset(ZoneOffset.UTC));
+ dto.status(ProvisioningStatusDto.fromValue(provisioning.getStatus().value()));
+ return dto;
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/SmsConfigurationDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/SmsConfigurationDtoConverter.java
new file mode 100644
index 00000000..9bea7d38
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/SmsConfigurationDtoConverter.java
@@ -0,0 +1,31 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.SMSConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.SMSConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateSMSConfigurationRequestParameters;
+
+public class SmsConfigurationDtoConverter {
+
+ public static SMSConfiguration convert(SMSConfigurationDto dto) {
+
+ if (null == dto) {
+ return null;
+ }
+ return new SMSConfiguration(
+ dto.getServicePlanId(),
+ dto.getCampaignId(),
+ ScheduledSmsProvisioningDtoConverter.convert(dto.getScheduledProvisioning()));
+ }
+
+ public static SMSConfigurationDto convert(
+ ActiveNumberUpdateSMSConfigurationRequestParameters configuration) {
+
+ if (null == configuration) {
+ return null;
+ }
+ SMSConfigurationDto dto = new SMSConfigurationDto();
+ dto.servicePlanId(configuration.getServicePlanId());
+ configuration.getCampaignId().ifPresent(dto::campaignId);
+ return dto;
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/VoiceConfigurationDtoConverter.java b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/VoiceConfigurationDtoConverter.java
new file mode 100644
index 00000000..9f7111f7
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/adapters/converters/VoiceConfigurationDtoConverter.java
@@ -0,0 +1,29 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import com.sinch.sdk.domains.numbers.models.VoiceConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.VoiceConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateVoiceConfigurationRequestParameters;
+
+public class VoiceConfigurationDtoConverter {
+
+ public static VoiceConfiguration convert(VoiceConfigurationDto dto) {
+
+ if (null == dto) {
+ return null;
+ }
+ return new VoiceConfiguration(
+ dto.getAppId(),
+ null != dto.getLastUpdatedTime() ? dto.getLastUpdatedTime().toInstant() : null,
+ ScheduledVoiceProvisioningDtoConverter.convert(dto.getScheduledVoiceProvisioning()));
+ }
+
+ public static VoiceConfigurationDto convert(
+ ActiveNumberUpdateVoiceConfigurationRequestParameters configuration) {
+
+ if (null == configuration) {
+ return null;
+ }
+
+ return new VoiceConfigurationDto().appId(configuration.getAppId());
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/ActiveNumber.java b/client/src/main/com/sinch/sdk/domains/numbers/models/ActiveNumber.java
new file mode 100644
index 00000000..854c4dcd
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/ActiveNumber.java
@@ -0,0 +1,288 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.time.Instant;
+import java.util.Collection;
+
+/**
+ * Active Number
+ *
+ * @since 1.0
+ */
+public class ActiveNumber {
+ private final String phoneNumber;
+
+ private final String projectId;
+
+ private final String displayName;
+
+ private final String regionCode;
+
+ private final NumberType type;
+
+ private final Collection capability;
+
+ private final Money money;
+
+ private final Integer paymentIntervalMonths;
+
+ private final Instant nextChargeDate;
+
+ private final Instant expireAt;
+
+ private final SMSConfiguration smsConfiguration;
+
+ private final VoiceConfiguration voiceConfiguration;
+
+ private final String callbackUrl;
+
+ /**
+ * @param phoneNumber The phone number in E.164 format with leading +. Example: +12025550134.
+ * @param projectId Project ID. Your project ID can be found on your Sinch Customer Dashboard.
+ * @param displayName User supplied name for the phone number.
+ * @param regionCode ISO 3166-1 alpha-2 country code of the phone number. Example US, UK or SE.
+ * @param type The number type.
+ * @param capability The capability of the number
+ * @param money An object giving details on currency code and the amount charged.
+ * @param paymentIntervalMonths How often the recurring price is charged in months.
+ * @param nextChargeDate The date of the next charge
+ * @param expireAt The timestamp when the subscription will expire if an expiration date has been
+ * set.
+ * @param smsConfiguration The current SMS configuration for this number.
+ * @param voiceConfiguration The current voice configuration for this number.
+ * @param callbackUrl The callback URL to be called for a rented number's provisioning /
+ * deprovisioning operations.
+ */
+ public ActiveNumber(
+ String phoneNumber,
+ String projectId,
+ String displayName,
+ String regionCode,
+ NumberType type,
+ Collection capability,
+ Money money,
+ Integer paymentIntervalMonths,
+ Instant nextChargeDate,
+ Instant expireAt,
+ SMSConfiguration smsConfiguration,
+ VoiceConfiguration voiceConfiguration,
+ String callbackUrl) {
+ this.phoneNumber = phoneNumber;
+ this.projectId = projectId;
+ this.displayName = displayName;
+ this.regionCode = regionCode;
+ this.type = type;
+ this.capability = capability;
+ this.money = money;
+ this.paymentIntervalMonths = paymentIntervalMonths;
+ this.nextChargeDate = nextChargeDate;
+ this.expireAt = expireAt;
+ this.smsConfiguration = smsConfiguration;
+ this.voiceConfiguration = voiceConfiguration;
+ this.callbackUrl = callbackUrl;
+ }
+
+ public String getPhoneNumber() {
+ return phoneNumber;
+ }
+
+ public String getProjectId() {
+ return projectId;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public NumberType getType() {
+ return type;
+ }
+
+ public Collection getCapability() {
+ return capability;
+ }
+
+ public Money getMoney() {
+ return money;
+ }
+
+ public Integer getPaymentIntervalMonths() {
+ return paymentIntervalMonths;
+ }
+
+ public Instant getNextChargeDate() {
+ return nextChargeDate;
+ }
+
+ public Instant getExpireAt() {
+ return expireAt;
+ }
+
+ public SMSConfiguration getSmsConfiguration() {
+ return smsConfiguration;
+ }
+
+ public VoiceConfiguration getVoiceConfiguration() {
+ return voiceConfiguration;
+ }
+
+ public String getCallbackUrl() {
+ return callbackUrl;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "ActiveNumber{"
+ + "phoneNumber='"
+ + phoneNumber
+ + '\''
+ + ", projectId='"
+ + projectId
+ + '\''
+ + ", displayName='"
+ + displayName
+ + '\''
+ + ", regionCode='"
+ + regionCode
+ + '\''
+ + ", type="
+ + type
+ + ", capability="
+ + capability
+ + ", money="
+ + money
+ + ", paymentIntervalMonths="
+ + paymentIntervalMonths
+ + ", nextChargeDate="
+ + nextChargeDate
+ + ", expireAt="
+ + expireAt
+ + ", smsConfiguration="
+ + smsConfiguration
+ + ", voiceConfiguration="
+ + voiceConfiguration
+ + ", callbackUrl='"
+ + callbackUrl
+ + '\''
+ + '}';
+ }
+
+ public static class Builder {
+ private String phoneNumber;
+
+ private String projectId;
+
+ private String displayName;
+
+ private String regionCode;
+
+ private NumberType type;
+
+ private Collection capability;
+
+ private Money money;
+
+ private Integer paymentIntervalMonths;
+
+ private Instant nextChargeDate;
+
+ private Instant expireAt;
+
+ private SMSConfiguration smsConfiguration;
+
+ private VoiceConfiguration voiceConfiguration;
+
+ private String callbackUrl;
+
+ private Builder() {}
+
+ public ActiveNumber build() {
+ return new ActiveNumber(
+ phoneNumber,
+ projectId,
+ displayName,
+ regionCode,
+ type,
+ capability,
+ money,
+ paymentIntervalMonths,
+ nextChargeDate,
+ expireAt,
+ smsConfiguration,
+ voiceConfiguration,
+ callbackUrl);
+ }
+
+ public Builder setPhoneNumber(String phoneNumber) {
+ this.phoneNumber = phoneNumber;
+ return this;
+ }
+
+ public Builder setProjectId(String projectId) {
+ this.projectId = projectId;
+ return this;
+ }
+
+ public Builder setDisplayName(String displayName) {
+ this.displayName = displayName;
+ return this;
+ }
+
+ public Builder setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ return this;
+ }
+
+ public Builder setType(NumberType type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder setCapability(Collection capability) {
+ this.capability = capability;
+ return this;
+ }
+
+ public Builder setMoney(Money money) {
+ this.money = money;
+ return this;
+ }
+
+ public Builder setPaymentIntervalMonths(Integer paymentIntervalMonths) {
+ this.paymentIntervalMonths = paymentIntervalMonths;
+ return this;
+ }
+
+ public Builder setNextChargeDate(Instant nextChargeDate) {
+ this.nextChargeDate = nextChargeDate;
+ return this;
+ }
+
+ public Builder setExpireAt(Instant expireAt) {
+ this.expireAt = expireAt;
+ return this;
+ }
+
+ public Builder setSmsConfiguration(SMSConfiguration smsConfiguration) {
+ this.smsConfiguration = smsConfiguration;
+ return this;
+ }
+
+ public Builder setVoiceConfiguration(VoiceConfiguration voiceConfiguration) {
+ this.voiceConfiguration = voiceConfiguration;
+ return this;
+ }
+
+ public Builder setCallbackUrl(String callbackUrl) {
+ this.callbackUrl = callbackUrl;
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/AvailableNumber.java b/client/src/main/com/sinch/sdk/domains/numbers/models/AvailableNumber.java
new file mode 100644
index 00000000..77f92940
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/AvailableNumber.java
@@ -0,0 +1,189 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.util.Collection;
+
+/**
+ * Active Number
+ *
+ * @since 1.0
+ */
+public class AvailableNumber {
+ private final String phoneNumber;
+
+ private final String regionCode;
+
+ private final NumberType type;
+
+ private final Collection capability;
+
+ private final Money setupPrice;
+
+ private final Money monthlyPrice;
+
+ private final Integer paymentIntervalMonths;
+
+ private final Boolean supportingDocumentationRequired;
+
+ /**
+ * @param phoneNumber The phone number in E.164 format with leading +. Example +12025550134.
+ * @param regionCode ISO 3166-1 alpha-2 country code of the phone number. Example: US, UK or SE.
+ * @param type The number type.
+ * @param capability The capability of the number.
+ * @param setupPrice An object giving details on currency code and the amount charged.
+ * @param monthlyPrice An object giving details on currency code and the amount charged.
+ * @param paymentIntervalMonths How often the recurring price is charged in months.
+ * @param supportingDocumentationRequired Whether or not supplementary documentation will be
+ * required to complete the number rental.
+ */
+ public AvailableNumber(
+ String phoneNumber,
+ String regionCode,
+ NumberType type,
+ Collection capability,
+ Money setupPrice,
+ Money monthlyPrice,
+ Integer paymentIntervalMonths,
+ Boolean supportingDocumentationRequired) {
+ this.phoneNumber = phoneNumber;
+ this.regionCode = regionCode;
+ this.type = type;
+ this.capability = capability;
+ this.setupPrice = setupPrice;
+ this.monthlyPrice = monthlyPrice;
+ this.paymentIntervalMonths = paymentIntervalMonths;
+ this.supportingDocumentationRequired = supportingDocumentationRequired;
+ }
+
+ public String getPhoneNumber() {
+ return phoneNumber;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public NumberType getType() {
+ return type;
+ }
+
+ public Collection getCapability() {
+ return capability;
+ }
+
+ public Money getSetupPrice() {
+ return setupPrice;
+ }
+
+ public Money getMonthlyPrice() {
+ return monthlyPrice;
+ }
+
+ public Integer getPaymentIntervalMonths() {
+ return paymentIntervalMonths;
+ }
+
+ public Boolean getSupportingDocumentationRequired() {
+ return supportingDocumentationRequired;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "AvailableNumber{"
+ + "phoneNumber='"
+ + phoneNumber
+ + '\''
+ + ", regionCode='"
+ + regionCode
+ + '\''
+ + ", type='"
+ + type
+ + '\''
+ + ", capability="
+ + capability
+ + ", setupPrice="
+ + setupPrice
+ + ", monthlyPrice="
+ + monthlyPrice
+ + ", paymentIntervalMonths="
+ + paymentIntervalMonths
+ + ", supportingDocumentationRequired="
+ + supportingDocumentationRequired
+ + '}';
+ }
+
+ public static class Builder {
+ private String phoneNumber;
+
+ private String regionCode;
+
+ private NumberType type;
+
+ private Collection capability;
+
+ private Money setupPrice;
+
+ private Money monthlyPrice;
+
+ private Integer paymentIntervalMonths;
+
+ private Boolean supportingDocumentationRequired;
+
+ private Builder() {}
+
+ public AvailableNumber build() {
+ return new AvailableNumber(
+ phoneNumber,
+ regionCode,
+ type,
+ capability,
+ setupPrice,
+ monthlyPrice,
+ paymentIntervalMonths,
+ supportingDocumentationRequired);
+ }
+
+ public Builder setPhoneNumber(String phoneNumber) {
+ this.phoneNumber = phoneNumber;
+ return this;
+ }
+
+ public Builder setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ return this;
+ }
+
+ public Builder setType(NumberType type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder setCapability(Collection capability) {
+ this.capability = capability;
+ return this;
+ }
+
+ public Builder setSetupPrice(Money setupPrice) {
+ this.setupPrice = setupPrice;
+ return this;
+ }
+
+ public Builder setMonthlyPrice(Money monthlyPrice) {
+ this.monthlyPrice = monthlyPrice;
+ return this;
+ }
+
+ public Builder setPaymentIntervalMonths(Integer paymentIntervalMonths) {
+ this.paymentIntervalMonths = paymentIntervalMonths;
+ return this;
+ }
+
+ public Builder setSupportingDocumentationRequired(Boolean supportingDocumentationRequired) {
+ this.supportingDocumentationRequired = supportingDocumentationRequired;
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/CallbackConfiguration.java b/client/src/main/com/sinch/sdk/domains/numbers/models/CallbackConfiguration.java
new file mode 100644
index 00000000..9fc758ae
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/CallbackConfiguration.java
@@ -0,0 +1,71 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+
+/**
+ * Callback configuration
+ *
+ * @since 1.0
+ */
+public class CallbackConfiguration {
+ private final String projectId;
+
+ private final String hmacSecret;
+
+ /**
+ * @param projectId ID of the project the configuration belongs to.
+ * @param hmacSecret The HMAC secret used for creating the callbacks X-Sinch-Signature header.
+ */
+ public CallbackConfiguration(String projectId, String hmacSecret) {
+ this.projectId = projectId;
+ this.hmacSecret = hmacSecret;
+ }
+
+ public String getProjectId() {
+ return projectId;
+ }
+
+ public String getHMACSecret() {
+ return hmacSecret;
+ }
+
+ @Override
+ public String toString() {
+ // do not output secret !
+ return "CallbackConfiguration{"
+ + "projectId='"
+ + projectId
+ + '\''
+ + ", hmacSecret='"
+ + "..."
+ + '\''
+ + '}';
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String projectId;
+
+ private String hmacSecret;
+
+ private Builder() {}
+
+ public CallbackConfiguration build() {
+ return new CallbackConfiguration(projectId, hmacSecret);
+ }
+
+ public Builder setProjectId(String projectId) {
+ this.projectId = projectId;
+ return this;
+ }
+
+ public Builder setHMACSecret(String hmacSecret) {
+ this.hmacSecret = hmacSecret;
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/Capability.java b/client/src/main/com/sinch/sdk/domains/numbers/models/Capability.java
new file mode 100644
index 00000000..597999fb
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/Capability.java
@@ -0,0 +1,38 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * Capability of a phone number
+ *
+ * @since 1.0
+ */
+public final class Capability extends EnumDynamic {
+ /** The SMS product can use the number. */
+ public static final Capability SMS = new Capability("SMS");
+
+ /** The Voice product can use the number. */
+ public static final Capability VOICE = new Capability("VOICE");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(Capability.class, Capability::new, Arrays.asList(SMS, VOICE));
+
+ private Capability(String value) {
+ super(value);
+ }
+
+ public static Stream values() {
+ return ENUM_SUPPORT.values();
+ }
+
+ public static Capability from(String value) {
+ return ENUM_SUPPORT.from(value);
+ }
+
+ public static String valueOf(Capability e) {
+ return ENUM_SUPPORT.valueOf(e);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/Money.java b/client/src/main/com/sinch/sdk/domains/numbers/models/Money.java
new file mode 100644
index 00000000..c9d63ee5
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/Money.java
@@ -0,0 +1,63 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+
+/**
+ * An object giving details on currency code and the amount charged.
+ *
+ * @since 1.0
+ */
+public class Money {
+ private final String currencyCode;
+
+ private final Double amount;
+
+ /**
+ * @param currencyCode The 3-letter currency code defined in ISO 4217.
+ * @param amount The amount. There are no guarantees on the precision unless documented by the
+ * message origin. The amount cannot be updated and is read-only.
+ */
+ public Money(String currencyCode, Double amount) {
+ this.currencyCode = currencyCode;
+ this.amount = amount;
+ }
+
+ public String getCurrencyCode() {
+ return currencyCode;
+ }
+
+ public Double getAmount() {
+ return amount;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "Money{" + "currencyCode='" + currencyCode + '\'' + ", amount='" + amount + '\'' + '}';
+ }
+
+ public static class Builder {
+ private String currencyCode;
+
+ private Double amount;
+
+ private Builder() {}
+
+ Builder setCurrencyCode(String value) {
+ this.currencyCode = value;
+ return this;
+ }
+
+ Builder setAmount(Double value) {
+ this.amount = value;
+ return this;
+ }
+
+ Money build() {
+ return new Money(this.currencyCode, this.amount);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/NumberPattern.java b/client/src/main/com/sinch/sdk/domains/numbers/models/NumberPattern.java
new file mode 100644
index 00000000..9505827e
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/NumberPattern.java
@@ -0,0 +1,69 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+
+/**
+ * An object enabling to identify number by pattern
+ *
+ * @since 1.0
+ */
+public class NumberPattern {
+
+ private final String pattern;
+ private final SearchPattern searchPattern;
+
+ /**
+ * @param pattern Sequence of digits to search for.
+ * @param searchPattern The pattern to apply to searches
+ */
+ public NumberPattern(String pattern, SearchPattern searchPattern) {
+ this.pattern = pattern;
+ this.searchPattern = searchPattern;
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ public SearchPattern getSearchPattern() {
+ return searchPattern;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "NumberPattern{"
+ + "pattern='"
+ + pattern
+ + '\''
+ + ", searchPattern='"
+ + searchPattern
+ + '\''
+ + '}';
+ }
+
+ public static class Builder {
+ private String pattern;
+
+ private SearchPattern searchPattern;
+
+ private Builder() {}
+
+ public Builder setPattern(String value) {
+ this.pattern = value;
+ return this;
+ }
+
+ public Builder setSearchPattern(SearchPattern value) {
+ this.searchPattern = value;
+ return this;
+ }
+
+ public NumberPattern build() {
+ return new NumberPattern(this.pattern, this.searchPattern);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/NumberType.java b/client/src/main/com/sinch/sdk/domains/numbers/models/NumberType.java
new file mode 100644
index 00000000..e4d58982
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/NumberType.java
@@ -0,0 +1,42 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * Type of phone number
+ *
+ * @since 1.0
+ */
+public final class NumberType extends EnumDynamic {
+
+ /** Numbers that belong to a specific range. */
+ public static final NumberType MOBILE = new NumberType("MOBILE");
+ /** Numbers that are assigned to a specific geographic region. */
+ public static final NumberType LOCAL = new NumberType("LOCAL");
+
+ /** Numbers that are free of charge for the calling party but billed for all arriving calls. */
+ public static final NumberType TOLL_FREE = new NumberType("TOLL_FREE");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(
+ NumberType.class, NumberType::new, Arrays.asList(MOBILE, LOCAL, TOLL_FREE));
+
+ private NumberType(String value) {
+ super(value);
+ }
+
+ public static Stream values() {
+ return ENUM_SUPPORT.values();
+ }
+
+ public static NumberType from(String value) {
+ return ENUM_SUPPORT.from(value);
+ }
+
+ public static String valueOf(NumberType e) {
+ return ENUM_SUPPORT.valueOf(e);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/OrderBy.java b/client/src/main/com/sinch/sdk/domains/numbers/models/OrderBy.java
new file mode 100644
index 00000000..9717c3e8
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/OrderBy.java
@@ -0,0 +1,38 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * Supported fields for ordering
+ *
+ * @since 1.0
+ */
+public final class OrderBy extends EnumDynamic {
+ /** Ordering by phoneNumber */
+ public static final OrderBy PHONE_NUMBER = new OrderBy("phoneNumber");
+ /** Ordering by displayName */
+ public static final OrderBy DISPLAY_NAME = new OrderBy("displayName");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(
+ OrderBy.class, OrderBy::new, Arrays.asList(PHONE_NUMBER, DISPLAY_NAME));
+
+ private OrderBy(String value) {
+ super(value);
+ }
+
+ public static Stream values() {
+ return ENUM_SUPPORT.values();
+ }
+
+ public static OrderBy from(String value) {
+ return ENUM_SUPPORT.from(value);
+ }
+
+ public static String valueOf(OrderBy e) {
+ return ENUM_SUPPORT.valueOf(e);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/ProvisioningStatus.java b/client/src/main/com/sinch/sdk/domains/numbers/models/ProvisioningStatus.java
new file mode 100644
index 00000000..4b9cd6a6
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/ProvisioningStatus.java
@@ -0,0 +1,51 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * Provisioning Status
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/error-codes/provisioning-errors/
+ * @since 1.0
+ */
+public final class ProvisioningStatus extends EnumDynamic {
+
+ public static final ProvisioningStatus PROVISIONING_STATUS_UNSPECIFIED =
+ new ProvisioningStatus("PROVISIONING_STATUS_UNSPECIFIED");
+ public static final ProvisioningStatus WAITING = new ProvisioningStatus("WAITING");
+ public static final ProvisioningStatus IN_PROGRESS = new ProvisioningStatus("IN_PROGRESS");
+ public static final ProvisioningStatus FAILED = new ProvisioningStatus("FAILED");
+ public static final ProvisioningStatus UNKNOWN_DEFAULT_OPEN_API =
+ new ProvisioningStatus("UNKNOWN_DEFAULT_OPEN_API");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(
+ ProvisioningStatus.class,
+ ProvisioningStatus::new,
+ Arrays.asList(
+ PROVISIONING_STATUS_UNSPECIFIED,
+ WAITING,
+ IN_PROGRESS,
+ FAILED,
+ UNKNOWN_DEFAULT_OPEN_API));
+
+ ProvisioningStatus(String value) {
+ super(value);
+ }
+
+ public static Stream values() {
+ return ENUM_SUPPORT.values();
+ }
+
+ public static ProvisioningStatus from(String value) {
+ return ENUM_SUPPORT.from(value);
+ }
+
+ public static String valueOf(ProvisioningStatus e) {
+ return ENUM_SUPPORT.valueOf(e);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/Region.java b/client/src/main/com/sinch/sdk/domains/numbers/models/Region.java
new file mode 100644
index 00000000..c4b26ae9
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/Region.java
@@ -0,0 +1,89 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import java.util.Collection;
+
+/**
+ * Region information related to assigned numbers
+ *
+ * @since 1.0
+ */
+public class Region {
+ private final String regionCode;
+
+ private final String regionName;
+
+ private final Collection types;
+
+ /**
+ * @param regionCode ISO 3166-1 alpha-2 region code. Examples: US, UK or SE.
+ * @param regionName Display name of the region. Examples: United States, United Kingdom or
+ * Sweden.
+ * @param types A list of the different number types available.
+ */
+ public Region(String regionCode, String regionName, Collection types) {
+ this.regionCode = regionCode;
+ this.regionName = regionName;
+ this.types = types;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public String getRegionName() {
+ return regionName;
+ }
+
+ public Collection getTypes() {
+ return types;
+ }
+
+ @Override
+ public String toString() {
+ return "AvailableRegion{"
+ + "regionCode='"
+ + regionCode
+ + '\''
+ + ", regionName='"
+ + regionName
+ + '\''
+ + ", types="
+ + types
+ + '}';
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String regionCode;
+
+ private String regionName;
+
+ private Collection types;
+
+ private Builder() {}
+
+ public Region build() {
+ return new Region(regionCode, regionName, types);
+ }
+
+ public Builder setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ return this;
+ }
+
+ public Builder setRegionName(String regionName) {
+ this.regionName = regionName;
+ return this;
+ }
+
+ public Builder setTypes(Collection types) {
+ this.types = types;
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/SMSConfiguration.java b/client/src/main/com/sinch/sdk/domains/numbers/models/SMSConfiguration.java
new file mode 100644
index 00000000..678d92c7
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/SMSConfiguration.java
@@ -0,0 +1,55 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.util.Optional;
+
+/** The SMS configuration for a number */
+public class SMSConfiguration {
+ private final String servicePlanId;
+
+ private final String campaignId;
+
+ private final ScheduledSmsProvisioning scheduledSmsProvisioning;
+
+ /**
+ * @param servicePlanId The servicePlanId can be found in the Sinch Customer Dashboard. The
+ * service plan ID is what ties this to the configured SMS service.
+ * @param campaignId Only for US phone numbers. This campaignId is required to send SMS traffic to
+ * US; click here to read more about 10DLC A2P messaging. So, it is the current campaign ID
+ * for this number. The campaignId is found on your TCR platform.
+ * @param scheduledSmsProvisioning This object is temporary and will appear while the scheduled
+ * provisioning for SMS is processing. Once it has successfully processed, only the ID of the
+ * SMS configuration will display.
+ */
+ public SMSConfiguration(
+ String servicePlanId, String campaignId, ScheduledSmsProvisioning scheduledSmsProvisioning) {
+ this.servicePlanId = servicePlanId;
+ this.campaignId = campaignId;
+ this.scheduledSmsProvisioning = scheduledSmsProvisioning;
+ }
+
+ public String getServicePlanId() {
+ return servicePlanId;
+ }
+
+ public Optional getCampaignId() {
+ return Optional.ofNullable(campaignId);
+ }
+
+ public Optional getScheduledSmsProvisioning() {
+ return Optional.ofNullable(scheduledSmsProvisioning);
+ }
+
+ @Override
+ public String toString() {
+ return "SMSConfiguration{"
+ + "servicePlanId='"
+ + servicePlanId
+ + '\''
+ + ", campaignId='"
+ + campaignId
+ + '\''
+ + ", scheduledSmsProvisioning="
+ + scheduledSmsProvisioning
+ + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/ScheduledSmsProvisioning.java b/client/src/main/com/sinch/sdk/domains/numbers/models/ScheduledSmsProvisioning.java
new file mode 100644
index 00000000..33f57ca0
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/ScheduledSmsProvisioning.java
@@ -0,0 +1,82 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.time.Instant;
+import java.util.Collection;
+
+/**
+ * Scheduled SMS provisioning information
+ *
+ * This object is temporary and will appear while the scheduled provisioning for SMS is
+ * processing. Once it has successfully processed, only the ID of the SMS configuration will
+ * display.
+ */
+public class ScheduledSmsProvisioning {
+ private final String servicePlanId;
+
+ private final String campaignId;
+
+ private final ProvisioningStatus status;
+
+ private final Instant lastUpdatedTime;
+
+ private final Collection errorCodes;
+
+ /**
+ * @param servicePlanId Service plan of the scheduled provisioning task.
+ * @param campaignId Campaign ID of the scheduled provisioning task. Note that the campaign ID is
+ * only for US numbers as it relates to 10DLC.
+ * @param status The provisioning status
+ * @param lastUpdatedTime when the status was last updated
+ * @param errorCodes The provisioning error codes
+ */
+ public ScheduledSmsProvisioning(
+ String servicePlanId,
+ String campaignId,
+ ProvisioningStatus status,
+ Instant lastUpdatedTime,
+ Collection errorCodes) {
+ this.servicePlanId = servicePlanId;
+ this.campaignId = campaignId;
+ this.status = status;
+ this.lastUpdatedTime = lastUpdatedTime;
+ this.errorCodes = errorCodes;
+ }
+
+ public String getServicePlanId() {
+ return servicePlanId;
+ }
+
+ public String getCampaignId() {
+ return campaignId;
+ }
+
+ public ProvisioningStatus getStatus() {
+ return status;
+ }
+
+ public Instant getLastUpdatedTime() {
+ return lastUpdatedTime;
+ }
+
+ public Collection getErrorCodes() {
+ return errorCodes;
+ }
+
+ @Override
+ public String toString() {
+ return "ScheduledSmsProvisioning{"
+ + "servicePlanId='"
+ + servicePlanId
+ + '\''
+ + ", campaignId='"
+ + campaignId
+ + '\''
+ + ", status="
+ + status
+ + ", lastUpdatedTime="
+ + lastUpdatedTime
+ + ", errorCodes="
+ + errorCodes
+ + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/ScheduledVoiceProvisioning.java b/client/src/main/com/sinch/sdk/domains/numbers/models/ScheduledVoiceProvisioning.java
new file mode 100644
index 00000000..9f38c604
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/ScheduledVoiceProvisioning.java
@@ -0,0 +1,55 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.time.Instant;
+
+/**
+ * Scheduled Voice provisioning information
+ *
+ * This object is temporary and will appear while the scheduled voice provisioning is processing.
+ * Once it has successfully processed, only the ID of the Voice configuration will display.
+ */
+public class ScheduledVoiceProvisioning {
+
+ private final String appId;
+
+ private final ProvisioningStatus status;
+
+ private final Instant lastUpdatedTime;
+
+ /**
+ * @param appId RTC application ID of the scheduled provisioning task.
+ * @param status The provisioning status
+ * @param lastUpdatedTime when the status was last updated
+ */
+ public ScheduledVoiceProvisioning(
+ String appId, ProvisioningStatus status, Instant lastUpdatedTime) {
+ this.appId = appId;
+ this.status = status;
+ this.lastUpdatedTime = lastUpdatedTime;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public ProvisioningStatus getStatus() {
+ return status;
+ }
+
+ public Instant getLastUpdatedTime() {
+ return lastUpdatedTime;
+ }
+
+ @Override
+ public String toString() {
+ return "ScheduledVoiceProvisioning{"
+ + "appId='"
+ + appId
+ + '\''
+ + ", status="
+ + status
+ + ", lastUpdatedTime="
+ + lastUpdatedTime
+ + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/SearchPattern.java b/client/src/main/com/sinch/sdk/domains/numbers/models/SearchPattern.java
new file mode 100644
index 00000000..f5e2323c
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/SearchPattern.java
@@ -0,0 +1,36 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+
+/**
+ * Search pattern for numbers
+ *
+ * @since 1.0
+ */
+public final class SearchPattern extends EnumDynamic {
+ /**
+ * Numbers that begin with the @see NumberPattern.getPattern entered.
+ *
+ * Often used to search for a specific area code. When using START, a plus sign (+) must be
+ * included and URL encoded, so %2B.
+ *
+ *
For example, to search for area code 206 in the US, you would enter, %2b1206
+ */
+ public static final SearchPattern START = new SearchPattern("START");
+ /**
+ * The number pattern entered is contained somewhere in the number, the location being undefined.
+ */
+ public static final SearchPattern CONTAINS = new SearchPattern("CONTAINS");
+ /** The number ends with the number pattern entered. */
+ public static final SearchPattern END = new SearchPattern("END");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(
+ SearchPattern.class, SearchPattern::new, Arrays.asList(START, CONTAINS, END));
+
+ private SearchPattern(String value) {
+ super(value);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/SmsErrorCode.java b/client/src/main/com/sinch/sdk/domains/numbers/models/SmsErrorCode.java
new file mode 100644
index 00000000..18007c3a
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/SmsErrorCode.java
@@ -0,0 +1,85 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * @see https://developers.sinch.com/docs/numbers/api-reference/error-codes/provisioning-errors/
+ * @since 1.0
+ */
+public final class SmsErrorCode extends EnumDynamic {
+ public static final SmsErrorCode ERROR_CODE_UNSPECIFIED =
+ new SmsErrorCode("ERROR_CODE_UNSPECIFIED");
+ public static final SmsErrorCode INTERNAL_ERROR = new SmsErrorCode("INTERNAL_ERROR");
+ public static final SmsErrorCode SMS_PROVISIONING_FAILED =
+ new SmsErrorCode("SMS_PROVISIONING_FAILED");
+ public static final SmsErrorCode CAMPAIGN_PROVISIONING_FAILED =
+ new SmsErrorCode("CAMPAIGN_PROVISIONING_FAILED");
+ public static final SmsErrorCode CAMPAIGN_NOT_AVAILABLE =
+ new SmsErrorCode("CAMPAIGN_NOT_AVAILABLE");
+ public static final SmsErrorCode EXCEEDED_10DLC_LIMIT = new SmsErrorCode("EXCEEDED_10DLC_LIMIT");
+ public static final SmsErrorCode NUMBER_PROVISIONING_FAILED =
+ new SmsErrorCode("NUMBER_PROVISIONING_FAILED");
+ public static final SmsErrorCode PARTNER_SERVICE_UNAVAILABLE =
+ new SmsErrorCode("PARTNER_SERVICE_UNAVAILABLE");
+ public static final SmsErrorCode CAMPAIGN_PENDING_ACCEPTANCE =
+ new SmsErrorCode("CAMPAIGN_PENDING_ACCEPTANCE");
+ public static final SmsErrorCode MNO_SHARING_ERROR = new SmsErrorCode("MNO_SHARING_ERROR");
+ public static final SmsErrorCode CAMPAIGN_EXPIRED = new SmsErrorCode("CAMPAIGN_EXPIRED");
+ public static final SmsErrorCode CAMPAIGN_MNO_REJECTED =
+ new SmsErrorCode("CAMPAIGN_MNO_REJECTED");
+ public static final SmsErrorCode CAMPAIGN_MNO_SUSPENDED =
+ new SmsErrorCode("CAMPAIGN_MNO_SUSPENDED");
+ public static final SmsErrorCode CAMPAIGN_MNO_REVIEW = new SmsErrorCode("CAMPAIGN_MNO_REVIEW");
+ public static final SmsErrorCode INSUFFICIENT_BALANCE = new SmsErrorCode("INSUFFICIENT_BALANCE");
+ public static final SmsErrorCode MOCK_CAMPAIGN_NOT_ALLOWED =
+ new SmsErrorCode("MOCK_CAMPAIGN_NOT_ALLOWED");
+ public static final SmsErrorCode TFN_NOT_ALLOWED = new SmsErrorCode("TFN_NOT_ALLOWED");
+ public static final SmsErrorCode INVALID_NNID = new SmsErrorCode("INVALID_NNID");
+ public static final SmsErrorCode UNKNOWN_DEFAULT_OPEN_API =
+ new SmsErrorCode("UNKNOWN_DEFAULT_OPEN_API");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(
+ SmsErrorCode.class,
+ SmsErrorCode::new,
+ Arrays.asList(
+ ERROR_CODE_UNSPECIFIED,
+ INTERNAL_ERROR,
+ SMS_PROVISIONING_FAILED,
+ CAMPAIGN_PROVISIONING_FAILED,
+ CAMPAIGN_NOT_AVAILABLE,
+ EXCEEDED_10DLC_LIMIT,
+ NUMBER_PROVISIONING_FAILED,
+ PARTNER_SERVICE_UNAVAILABLE,
+ CAMPAIGN_PENDING_ACCEPTANCE,
+ MNO_SHARING_ERROR,
+ CAMPAIGN_EXPIRED,
+ CAMPAIGN_MNO_REJECTED,
+ CAMPAIGN_MNO_SUSPENDED,
+ CAMPAIGN_MNO_REVIEW,
+ INSUFFICIENT_BALANCE,
+ MOCK_CAMPAIGN_NOT_ALLOWED,
+ TFN_NOT_ALLOWED,
+ INVALID_NNID,
+ UNKNOWN_DEFAULT_OPEN_API));
+
+ SmsErrorCode(String value) {
+ super(value);
+ }
+
+ public static Stream values() {
+ return ENUM_SUPPORT.values();
+ }
+
+ public static SmsErrorCode from(String value) {
+ return ENUM_SUPPORT.from(value);
+ }
+
+ public static String valueOf(SmsErrorCode e) {
+ return ENUM_SUPPORT.valueOf(e);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/VoiceConfiguration.java b/client/src/main/com/sinch/sdk/domains/numbers/models/VoiceConfiguration.java
new file mode 100644
index 00000000..d596c380
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/VoiceConfiguration.java
@@ -0,0 +1,59 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.time.Instant;
+import java.util.Optional;
+
+/**
+ * The voice configuration for a number
+ *
+ * @since 1.0
+ */
+public class VoiceConfiguration {
+ private final String appId;
+
+ private final Instant lastUpdatedTime;
+
+ private final ScheduledVoiceProvisioning scheduledVoiceProvisioning;
+
+ /**
+ * @param appId Your app ID for the Voice API. The appId can be found in your Sinch Customer
+ * Dashboard under Voice, then apps.
+ * @param lastUpdatedTime when the status was last updated
+ * @param scheduledVoiceProvisioning This object is temporary and will appear while the scheduled
+ * voice provisioning is processing. Once it has successfully processed, only the ID of the
+ * Voice configuration will display.
+ */
+ public VoiceConfiguration(
+ String appId,
+ Instant lastUpdatedTime,
+ ScheduledVoiceProvisioning scheduledVoiceProvisioning) {
+ this.appId = appId;
+ this.lastUpdatedTime = lastUpdatedTime;
+ this.scheduledVoiceProvisioning = scheduledVoiceProvisioning;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public Optional getLastUpdatedTime() {
+ return Optional.ofNullable(lastUpdatedTime);
+ }
+
+ public Optional getScheduledVoiceProvisioning() {
+ return Optional.ofNullable(scheduledVoiceProvisioning);
+ }
+
+ @Override
+ public String toString() {
+ return "VoiceConfiguration{"
+ + "appId='"
+ + appId
+ + '\''
+ + ", lastUpdatedTime="
+ + lastUpdatedTime
+ + ", scheduledVoiceProvisioning="
+ + scheduledVoiceProvisioning
+ + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/package-info.java b/client/src/main/com/sinch/sdk/domains/numbers/models/package-info.java
new file mode 100644
index 00000000..e06d5c10
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Numbers API related models
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.domains.numbers.models;
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParameters.java
new file mode 100644
index 00000000..377f53b2
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParameters.java
@@ -0,0 +1,168 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.OrderBy;
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Parameters request to list active numbers for a project
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Active-Number/
+ * @since 1.0
+ */
+public class ActiveNumberListRequestParameters {
+ private final String regionCode;
+ private final NumberType type;
+ private final NumberPattern numberPattern;
+ private final Collection capabilities;
+ private final Integer pageSize;
+ private final String pageToken;
+ private final OrderBy orderBy;
+
+ /**
+ * @param regionCode Region code to filter by. ISO 3166-1 alpha-2 country code of the phone
+ * number. Example: US, GB or SE.
+ * @param type Number type to filter by
+ * @param numberPattern Pattern to search for
+ * @param capabilities Number capabilities to filter by
+ * @param pageSize The maximum number of items to return.
+ * @param pageToken The next page token value returned from a previous List request, if any
+ * @param orderBy Ordering results
+ */
+ public ActiveNumberListRequestParameters(
+ String regionCode,
+ NumberType type,
+ NumberPattern numberPattern,
+ Collection capabilities,
+ Integer pageSize,
+ String pageToken,
+ OrderBy orderBy) {
+ this.regionCode = regionCode;
+ this.type = type;
+ this.numberPattern = numberPattern;
+ this.capabilities = capabilities;
+ this.pageSize = pageSize;
+ this.pageToken = pageToken;
+ this.orderBy = orderBy;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public NumberType getType() {
+ return type;
+ }
+
+ public Optional getNumberPattern() {
+ return Optional.ofNullable(numberPattern);
+ }
+
+ public Optional> getCapabilities() {
+ return Optional.ofNullable(capabilities);
+ }
+
+ public Optional getPageSize() {
+ return Optional.ofNullable(pageSize);
+ }
+
+ public Optional getPageToken() {
+ return Optional.ofNullable(pageToken);
+ }
+
+ public Optional getOrderBy() {
+ return Optional.ofNullable(orderBy);
+ }
+
+ @Override
+ public String toString() {
+ return "ActiveNumberListRequestParameters{"
+ + "regionCode='"
+ + regionCode
+ + '\''
+ + ", type="
+ + type
+ + ", numberPattern="
+ + numberPattern
+ + ", capabilities="
+ + capabilities
+ + ", pageSize="
+ + pageSize
+ + ", pageToken="
+ + pageToken
+ + ", orderBy="
+ + orderBy
+ + '}';
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String regionCode;
+ NumberType type;
+ NumberPattern numberPattern;
+ Collection capabilities;
+ Integer pageSize;
+ String pageToken;
+ OrderBy orderBy;
+
+ private Builder() {}
+
+ public Builder(ActiveNumberListRequestParameters parameters) {
+ this.setRegionCode(parameters.regionCode)
+ .setType(parameters.type)
+ .setNumberPattern(parameters.numberPattern)
+ .setCapabilities(parameters.capabilities)
+ .setPageSize(parameters.pageSize)
+ .setPageToken(parameters.pageToken)
+ .setOrderBy(parameters.orderBy);
+ }
+
+ public Builder setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ return this;
+ }
+
+ public Builder setType(NumberType type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder setNumberPattern(NumberPattern numberPattern) {
+ this.numberPattern = numberPattern;
+ return this;
+ }
+
+ public Builder setCapabilities(Collection capabilities) {
+ this.capabilities = capabilities;
+ return this;
+ }
+
+ public Builder setPageSize(Integer pageSize) {
+ this.pageSize = pageSize;
+ return this;
+ }
+
+ public Builder setPageToken(String pageToken) {
+ this.pageToken = pageToken;
+ return this;
+ }
+
+ public Builder setOrderBy(OrderBy orderBy) {
+ this.orderBy = orderBy;
+ return this;
+ }
+
+ public ActiveNumberListRequestParameters build() {
+ return new ActiveNumberListRequestParameters(
+ regionCode, type, numberPattern, capabilities, pageSize, pageToken, orderBy);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateRequestParameters.java
new file mode 100644
index 00000000..734cb6e8
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateRequestParameters.java
@@ -0,0 +1,92 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import java.util.Optional;
+
+/**
+ * Parameters request to update an active number for a project
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Active-Number/#tag/Active-Number/operation/NumberService_UpdateActiveNumber
+ * @since 1.0
+ */
+public class ActiveNumberUpdateRequestParameters {
+ private final String displayName;
+ private final ActiveNumberUpdateSMSConfigurationRequestParameters smsConfiguration;
+ private final ActiveNumberUpdateVoiceConfigurationRequestParameters voiceConfiguration;
+ private final String callback;
+
+ /**
+ * @param displayName User supplied name for the phone number
+ * @param smsConfiguration The current SMS configuration for this number
+ * @param voiceConfiguration The current voice configuration for this number
+ * @param callback The callback URL to be called for a rented number's provisioning /
+ * deprovisioning operations
+ */
+ public ActiveNumberUpdateRequestParameters(
+ String displayName,
+ ActiveNumberUpdateSMSConfigurationRequestParameters smsConfiguration,
+ ActiveNumberUpdateVoiceConfigurationRequestParameters voiceConfiguration,
+ String callback) {
+ this.displayName = displayName;
+ this.smsConfiguration = smsConfiguration;
+ this.voiceConfiguration = voiceConfiguration;
+ this.callback = callback;
+ }
+
+ public Optional getDisplayName() {
+ return Optional.ofNullable(displayName);
+ }
+
+ public Optional getSmsConfiguration() {
+ return Optional.ofNullable(smsConfiguration);
+ }
+
+ public Optional getVoiceConfiguration() {
+ return Optional.ofNullable(voiceConfiguration);
+ }
+
+ public Optional getCallback() {
+ return Optional.ofNullable(callback);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String displayName;
+ ActiveNumberUpdateSMSConfigurationRequestParameters smsConfiguration;
+ ActiveNumberUpdateVoiceConfigurationRequestParameters voiceConfiguration;
+ String callback;
+
+ private Builder() {}
+
+ public Builder setDisplayName(String displayName) {
+ this.displayName = displayName;
+ return this;
+ }
+
+ public Builder setSmsConfiguration(
+ ActiveNumberUpdateSMSConfigurationRequestParameters smsConfiguration) {
+ this.smsConfiguration = smsConfiguration;
+ return this;
+ }
+
+ public Builder setVoiceConfiguration(
+ ActiveNumberUpdateVoiceConfigurationRequestParameters voiceConfiguration) {
+ this.voiceConfiguration = voiceConfiguration;
+ return this;
+ }
+
+ public Builder setCallback(String callback) {
+ this.callback = callback;
+ return this;
+ }
+
+ public ActiveNumberUpdateRequestParameters build() {
+ return new ActiveNumberUpdateRequestParameters(
+ displayName, smsConfiguration, voiceConfiguration, callback);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateSMSConfigurationRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateSMSConfigurationRequestParameters.java
new file mode 100644
index 00000000..93ca4008
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateSMSConfigurationRequestParameters.java
@@ -0,0 +1,75 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import java.util.Optional;
+
+/***
+ * SMS configuration parameters request to update an active number for a project
+ * @since 1.0
+ */
+public class ActiveNumberUpdateSMSConfigurationRequestParameters {
+ private final String servicePlanId;
+
+ private final String campaignId;
+
+ /**
+ * @param servicePlanId The servicePlanId can be found in the Sinch Customer Dashboard. The
+ * service plan ID is what ties this number to the configured SMS service.
+ * @param campaignId Only for US phone numbers. This campaignId is required to send SMS traffic to
+ * US; click here to read more about 10DLC A2P messaging. So, it is the current campaign ID
+ * for this number. The campaignId is found on your TCR platform.
+ */
+ public ActiveNumberUpdateSMSConfigurationRequestParameters(
+ String servicePlanId, String campaignId) {
+ this.servicePlanId = servicePlanId;
+ this.campaignId = campaignId;
+ }
+
+ public ActiveNumberUpdateSMSConfigurationRequestParameters(String servicePlanId) {
+ this(servicePlanId, null);
+ }
+
+ public String getServicePlanId() {
+ return servicePlanId;
+ }
+
+ public Optional getCampaignId() {
+ return Optional.ofNullable(campaignId);
+ }
+
+ @Override
+ public String toString() {
+ return "ActiveNumberUpdateSMSConfigurationRequestParameters{"
+ + "servicePlanId='"
+ + servicePlanId
+ + '\''
+ + ", campaignId="
+ + campaignId
+ + '}';
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String servicePlanId;
+ String campaignId;
+
+ private Builder() {}
+
+ public Builder setServicePlanId(String servicePlanId) {
+ this.servicePlanId = servicePlanId;
+ return this;
+ }
+
+ public Builder setCampaignId(String campaignId) {
+ this.campaignId = campaignId;
+ return this;
+ }
+
+ public ActiveNumberUpdateSMSConfigurationRequestParameters build() {
+ return new ActiveNumberUpdateSMSConfigurationRequestParameters(servicePlanId, campaignId);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateVoiceConfigurationRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateVoiceConfigurationRequestParameters.java
new file mode 100644
index 00000000..0989c0a6
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberUpdateVoiceConfigurationRequestParameters.java
@@ -0,0 +1,52 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+
+/***
+ * SMS configuration parameters request to update an active number for a project
+ * @since 1.0
+ */
+
+public class ActiveNumberUpdateVoiceConfigurationRequestParameters {
+ private final String appId;
+
+ /**
+ * @param appId Your app ID for the Voice API. The appId can be found in your Sinch Customer
+ * Dashboard under Voice, then apps.
+ */
+ public ActiveNumberUpdateVoiceConfigurationRequestParameters(String appId) {
+ this.appId = appId;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ @Override
+ public String toString() {
+ return "ActiveNumberUpdateVoiceConfigurationRequestParameters{"
+ + "appId='"
+ + appId
+ + '\''
+ + '}';
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String appId;
+
+ private Builder() {}
+
+ public Builder setAppId(String appId) {
+ this.appId = appId;
+ return this;
+ }
+
+ public ActiveNumberUpdateVoiceConfigurationRequestParameters build() {
+ return new ActiveNumberUpdateVoiceConfigurationRequestParameters(appId);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParameters.java
new file mode 100644
index 00000000..65be9f07
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParameters.java
@@ -0,0 +1,108 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Parameters request to list available numbers for a project
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Available-Number/#tag/Available-Number/operation/NumberService_ListAvailableNumbers/
+ * @since 1.0
+ */
+public class AvailableNumberListAllRequestParameters {
+ private final String regionCode;
+ private final NumberType type;
+ private final NumberPattern numberPattern;
+ private final Collection capabilities;
+ private final Integer size;
+
+ /**
+ * @param regionCode Region code to filter by. ISO 3166-1 alpha-2 country code of the phone
+ * number. Example: US, GB or SE.
+ * @param type Number type to filter by
+ * @param numberPattern Search pattern
+ * @param capabilities Capabilities to filter by
+ * @param size Optional. The maximum number of items to return.
+ */
+ public AvailableNumberListAllRequestParameters(
+ String regionCode,
+ NumberType type,
+ NumberPattern numberPattern,
+ Collection capabilities,
+ Integer size) {
+ this.regionCode = regionCode;
+ this.type = type;
+ this.numberPattern = numberPattern;
+ this.capabilities = capabilities;
+ this.size = size;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public NumberType getType() {
+ return type;
+ }
+
+ public Optional getNumberPattern() {
+ return Optional.ofNullable(numberPattern);
+ }
+
+ public Optional> getCapabilities() {
+ return Optional.ofNullable(capabilities);
+ }
+
+ public Optional getSize() {
+ return Optional.ofNullable(size);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String regionCode;
+ NumberType type;
+ NumberPattern numberPattern;
+ Collection capabilities;
+ Integer size;
+
+ private Builder() {}
+
+ public Builder setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ return this;
+ }
+
+ public Builder setType(NumberType type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder setNumberPattern(NumberPattern numberPattern) {
+ this.numberPattern = numberPattern;
+ return this;
+ }
+
+ public Builder setCapabilities(Collection capabilities) {
+ this.capabilities = capabilities;
+ return this;
+ }
+
+ public Builder setSize(Integer size) {
+ this.size = size;
+ return this;
+ }
+
+ public AvailableNumberListAllRequestParameters build() {
+ return new AvailableNumberListAllRequestParameters(
+ regionCode, type, numberPattern, capabilities, size);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentAnyRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentAnyRequestParameters.java
new file mode 100644
index 00000000..72235ff0
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentAnyRequestParameters.java
@@ -0,0 +1,133 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Parameters request to rent a number using criteria
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Available-Number/#tag/Available-Number/operation/NumberService_ListAvailableNumbers/
+ * @since 1.0
+ */
+public class AvailableNumberRentAnyRequestParameters {
+ private final String regionCode;
+ private final NumberType type;
+ private final NumberPattern numberPattern;
+ private final Collection capabilities;
+ private final RentSMSConfigurationRequestParameters smsConfiguration;
+ private final RentVoiceConfigurationRequestParameters voiceConfiguration;
+ private final String callbackUrl;
+
+ public AvailableNumberRentAnyRequestParameters(
+ String regionCode,
+ NumberType type,
+ NumberPattern numberPattern,
+ Collection capabilities,
+ RentSMSConfigurationRequestParameters smsConfiguration,
+ RentVoiceConfigurationRequestParameters voiceConfiguration,
+ String callbackUrl) {
+ this.regionCode = regionCode;
+ this.type = type;
+ this.numberPattern = numberPattern;
+ this.capabilities = capabilities;
+ this.smsConfiguration = smsConfiguration;
+ this.voiceConfiguration = voiceConfiguration;
+ this.callbackUrl = callbackUrl;
+ }
+
+ public String getRegionCode() {
+ return regionCode;
+ }
+
+ public NumberType getType() {
+ return type;
+ }
+
+ public Optional getNumberPattern() {
+ return Optional.ofNullable(numberPattern);
+ }
+
+ public Optional> getCapabilities() {
+ return Optional.ofNullable(capabilities);
+ }
+
+ public Optional getSmsConfiguration() {
+ return Optional.ofNullable(smsConfiguration);
+ }
+
+ public Optional getVoiceConfiguration() {
+ return Optional.ofNullable(voiceConfiguration);
+ }
+
+ public Optional getCallBackUrl() {
+ return Optional.ofNullable(callbackUrl);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String regionCode;
+ NumberType type;
+ NumberPattern numberPattern;
+ Collection capabilities;
+ RentSMSConfigurationRequestParameters smsConfiguration;
+ RentVoiceConfigurationRequestParameters voiceConfiguration;
+ String callbackUrl;
+
+ private Builder() {}
+
+ public Builder setRegionCode(String regionCode) {
+ this.regionCode = regionCode;
+ return this;
+ }
+
+ public Builder setType(NumberType type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder setNumberPattern(NumberPattern numberPattern) {
+ this.numberPattern = numberPattern;
+ return this;
+ }
+
+ public Builder setCapabilities(Collection capabilities) {
+ this.capabilities = capabilities;
+ return this;
+ }
+
+ public Builder setSmsConfiguration(RentSMSConfigurationRequestParameters smsConfiguration) {
+ this.smsConfiguration = smsConfiguration;
+ return this;
+ }
+
+ public Builder setVoiceConfiguration(
+ RentVoiceConfigurationRequestParameters voiceConfiguration) {
+ this.voiceConfiguration = voiceConfiguration;
+ return this;
+ }
+
+ public Builder setCallbackUrl(String callbackUrl) {
+ this.callbackUrl = callbackUrl;
+ return this;
+ }
+
+ public AvailableNumberRentAnyRequestParameters build() {
+ return new AvailableNumberRentAnyRequestParameters(
+ regionCode,
+ type,
+ numberPattern,
+ capabilities,
+ smsConfiguration,
+ voiceConfiguration,
+ callbackUrl);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParameters.java
new file mode 100644
index 00000000..8227363a
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParameters.java
@@ -0,0 +1,81 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import java.util.Optional;
+
+/**
+ * Parameters request to rent a number
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Available-Number/#tag/Available-Number/operation/NumberService_RentNumber
+ * @since 1.0
+ */
+public class AvailableNumberRentRequestParameters {
+ private final RentSMSConfigurationRequestParameters smsConfiguration;
+ private final RentVoiceConfigurationRequestParameters voiceConfiguration;
+ private final String callbackUrl;
+
+ /**
+ * @param smsConfiguration The current SMS configuration for this number
+ * @param voiceConfiguration The current voice configuration for this number. During scheduled
+ * provisioning, the app ID value may be empty in a response if it is still processing or if
+ * it has failed. The status of scheduled provisioning will show under a
+ * scheduledVoiceProvisioning object if it's still running. Once processed successfully, the
+ * appId sent will appear directly under the voiceConfiguration object.
+ * @param callbackUrl The callback URL to be called for a rented number's provisioning /
+ * deprovisioning operations.
+ */
+ public AvailableNumberRentRequestParameters(
+ RentSMSConfigurationRequestParameters smsConfiguration,
+ RentVoiceConfigurationRequestParameters voiceConfiguration,
+ String callbackUrl) {
+ this.smsConfiguration = smsConfiguration;
+ this.voiceConfiguration = voiceConfiguration;
+ this.callbackUrl = callbackUrl;
+ }
+
+ public Optional getSmsConfiguration() {
+ return Optional.of(smsConfiguration);
+ }
+
+ public Optional getVoiceConfiguration() {
+ return Optional.of(voiceConfiguration);
+ }
+
+ public Optional getCallBackUrl() {
+ return Optional.of(callbackUrl);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ RentSMSConfigurationRequestParameters smsConfiguration;
+ RentVoiceConfigurationRequestParameters voiceConfiguration;
+ String callbackUrl;
+
+ private Builder() {}
+
+ public Builder setSmsConfiguration(RentSMSConfigurationRequestParameters smsConfiguration) {
+ this.smsConfiguration = smsConfiguration;
+ return this;
+ }
+
+ public Builder setVoiceConfiguration(
+ RentVoiceConfigurationRequestParameters voiceConfiguration) {
+ this.voiceConfiguration = voiceConfiguration;
+ return this;
+ }
+
+ public Builder setCallbackUrl(String callbackUrl) {
+ this.callbackUrl = callbackUrl;
+ return this;
+ }
+
+ public AvailableNumberRentRequestParameters build() {
+ return new AvailableNumberRentRequestParameters(
+ smsConfiguration, voiceConfiguration, callbackUrl);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParameters.java
new file mode 100644
index 00000000..543e89e4
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParameters.java
@@ -0,0 +1,46 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Parameters request to list all regions by criteria
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/numbers/tag/Available-Regions/
+ * @since 1.0
+ */
+public class AvailableRegionListAllRequestParameters {
+
+ private final Collection types;
+
+ /** @param types Only return regions for which numbers are provided with the given types */
+ public AvailableRegionListAllRequestParameters(Collection types) {
+ this.types = types;
+ }
+
+ public Optional> getTypes() {
+ return Optional.ofNullable(types);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ Collection types;
+
+ private Builder() {}
+
+ public Builder setTypes(Collection types) {
+ this.types = types;
+ return this;
+ }
+
+ public AvailableRegionListAllRequestParameters build() {
+ return new AvailableRegionListAllRequestParameters(types);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParameters.java
new file mode 100644
index 00000000..3afb2f88
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParameters.java
@@ -0,0 +1,43 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+
+/**
+ * Parameters request to update callback configuration
+ *
+ * @see https://developers.sinch.com/docs/numbers/api-reference/callbacks-numbers/tag/Callback-Configuration/#tag/Callback-Configuration/operation/UpdateCallbackConfiguration
+ * @since 1.0
+ */
+public class CallbackConfigurationUpdateRequestParameters {
+ /** */
+ private final String hmacSecret;
+
+ /** @param hmacSecret The HMAC secret to be updated for the specified project */
+ public CallbackConfigurationUpdateRequestParameters(String hmacSecret) {
+ this.hmacSecret = hmacSecret;
+ }
+
+ public String getHMACSecret() {
+ return hmacSecret;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String hmacSecret;
+
+ private Builder() {}
+
+ public Builder setHMACSecret(String hmacSecret) {
+ this.hmacSecret = hmacSecret;
+ return this;
+ }
+
+ public CallbackConfigurationUpdateRequestParameters build() {
+ return new CallbackConfigurationUpdateRequestParameters(hmacSecret);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParameters.java
new file mode 100644
index 00000000..9820089c
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParameters.java
@@ -0,0 +1,63 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.ActiveNumber.Builder;
+import java.util.Optional;
+
+/**
+ * SMS configuration parameters request to rent a number
+ *
+ * @since 1.0
+ */
+public class RentSMSConfigurationRequestParameters {
+ private final String servicePlanId;
+ private final String campaignId;
+
+ /**
+ * @param servicePlanId The servicePlanId can be found in the Sinch Customer Dashboard. The
+ * service plan ID is what ties this number to the configured SMS service.
+ * @param campaignId Only for US phone numbers. This campaignId is required to send SMS traffic to
+ * US; click here to read more about 10DLC A2P messaging. So, it is the current campaign ID
+ * for this number. The campaignId is found on your TCR platform.
+ */
+ public RentSMSConfigurationRequestParameters(String servicePlanId, String campaignId) {
+ this.servicePlanId = servicePlanId;
+ this.campaignId = campaignId;
+ }
+
+ public RentSMSConfigurationRequestParameters(String servicePlanId) {
+ this(servicePlanId, null);
+ }
+
+ public String getServicePlanId() {
+ return servicePlanId;
+ }
+
+ public Optional getCampaignId() {
+ return Optional.ofNullable(this.campaignId);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String servicePlanId;
+ String campaignId;
+
+ private Builder() {}
+
+ public Builder setServicePlanId(String servicePlanId) {
+ this.servicePlanId = servicePlanId;
+ return this;
+ }
+
+ public Builder setCampaignId(String campaignId) {
+ this.campaignId = campaignId;
+ return this;
+ }
+
+ public RentSMSConfigurationRequestParameters build() {
+ return new RentSMSConfigurationRequestParameters(servicePlanId, campaignId);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParameters.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParameters.java
new file mode 100644
index 00000000..148ce6ad
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParameters.java
@@ -0,0 +1,41 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+/**
+ * Voice configuration parameters request to rent a number
+ *
+ * @since 1.0
+ */
+public class RentVoiceConfigurationRequestParameters {
+ private final String appId;
+
+ /**
+ * @param appId Your app ID for the Voice API. The appId can be found in your Sinch Customer
+ * Dashboard under Voice, then apps.
+ */
+ public RentVoiceConfigurationRequestParameters(String appId) {
+ this.appId = appId;
+ }
+
+ public String getAppId() {
+ return appId;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ String appId;
+
+ private Builder() {}
+
+ public Builder setAppId(String appId) {
+ this.appId = appId;
+ return this;
+ }
+
+ public RentVoiceConfigurationRequestParameters build() {
+ return new RentVoiceConfigurationRequestParameters(appId);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/requests/package-info.java b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/package-info.java
new file mode 100644
index 00000000..baf5491d
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/requests/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Numbers API requests related models
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.domains.numbers.models.requests;
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/responses/ActiveNumberListResponse.java b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/ActiveNumberListResponse.java
new file mode 100644
index 00000000..f2671a4b
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/ActiveNumberListResponse.java
@@ -0,0 +1,53 @@
+package com.sinch.sdk.domains.numbers.models.responses;
+
+import com.sinch.sdk.core.models.pagination.ListResponse;
+import com.sinch.sdk.core.models.pagination.Page;
+import com.sinch.sdk.core.utils.StringUtil;
+import com.sinch.sdk.domains.numbers.ActiveNumberService;
+import com.sinch.sdk.domains.numbers.models.ActiveNumber;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberListRequestParameters;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+/**
+ * Lists all active numbers for a project
+ *
+ * @since 1.0
+ */
+public class ActiveNumberListResponse extends ListResponse {
+
+ private final Page page;
+ private final ActiveNumberService service;
+
+ public ActiveNumberListResponse(
+ ActiveNumberService service,
+ Page page) {
+ this.service = service;
+ this.page = page;
+ }
+
+ public boolean hasNextPage() {
+ return (null != page.getNextPageToken()
+ && !StringUtil.isEmpty(page.getNextPageToken().getToken()));
+ }
+
+ public ActiveNumberListResponse nextPage() {
+ if (!hasNextPage()) {
+ throw new NoSuchElementException("Reached the last page of the API response");
+ }
+ ActiveNumberListRequestParameters.Builder newParameters =
+ new ActiveNumberListRequestParameters.Builder(page.getParameters());
+ String nextToken = page.getNextPageToken().getToken();
+ newParameters.setPageToken(nextToken);
+ return service.list(newParameters.build());
+ }
+
+ public Collection getContent() {
+ return page.getEntities();
+ }
+
+ @Override
+ public String toString() {
+ return "ActiveNumberListResponse{" + "page=" + page + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/responses/AvailableNumberListResponse.java b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/AvailableNumberListResponse.java
new file mode 100644
index 00000000..b3310495
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/AvailableNumberListResponse.java
@@ -0,0 +1,37 @@
+package com.sinch.sdk.domains.numbers.models.responses;
+
+import com.sinch.sdk.core.models.pagination.ListResponse;
+import com.sinch.sdk.domains.numbers.models.AvailableNumber;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+/**
+ * Lists all available numbers
+ *
+ * @since 1.0
+ */
+public class AvailableNumberListResponse extends ListResponse {
+
+ Collection content;
+
+ public AvailableNumberListResponse(Collection list) {
+ this.content = list;
+ }
+
+ public boolean hasNextPage() {
+ return false;
+ }
+
+ public AvailableNumberListResponse nextPage() {
+ throw new NoSuchElementException("Reached the last page of the API response");
+ }
+
+ public Collection getContent() {
+ return content;
+ }
+
+ @Override
+ public String toString() {
+ return "AvailableNumberListResponse{" + "content=" + content + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/responses/AvailableRegionListResponse.java b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/AvailableRegionListResponse.java
new file mode 100644
index 00000000..927a6ede
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/AvailableRegionListResponse.java
@@ -0,0 +1,37 @@
+package com.sinch.sdk.domains.numbers.models.responses;
+
+import com.sinch.sdk.core.models.pagination.ListResponse;
+import com.sinch.sdk.domains.numbers.models.Region;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+/**
+ * Lists all regions for numbers provided for the project ID.
+ *
+ * @since 1.0
+ */
+public class AvailableRegionListResponse extends ListResponse {
+
+ Collection content;
+
+ public AvailableRegionListResponse(Collection list) {
+ this.content = list;
+ }
+
+ public boolean hasNextPage() {
+ return false;
+ }
+
+ public AvailableRegionListResponse nextPage() {
+ throw new NoSuchElementException("Reached the last page of the API response");
+ }
+
+ public Collection getContent() {
+ return content;
+ }
+
+ @Override
+ public String toString() {
+ return "AvailableRegionListResponse{" + "content=" + content + '}';
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/models/responses/package-info.java b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/package-info.java
new file mode 100644
index 00000000..9fa13e9f
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/models/responses/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Numbers API response related models
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.domains.numbers.models.responses;
diff --git a/client/src/main/com/sinch/sdk/domains/numbers/package-info.java b/client/src/main/com/sinch/sdk/domains/numbers/package-info.java
new file mode 100644
index 00000000..9944337d
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/numbers/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Numbers API interface
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.domains.numbers;
diff --git a/client/src/main/com/sinch/sdk/domains/sms/BatchesService.java b/client/src/main/com/sinch/sdk/domains/sms/BatchesService.java
new file mode 100644
index 00000000..f6b2efe6
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/BatchesService.java
@@ -0,0 +1,23 @@
+package com.sinch.sdk.domains.sms;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.sms.models.Batch;
+
+/**
+ * Batches Service
+ *
+ * @see https://developers.sinch.com/docs/sms/api-reference/sms/tag/Batches/
+ * @since 1.0
+ */
+public interface BatchesService {
+
+ /**
+ * Get a batch message
+ *
+ * @param batchId The batch ID you received from sending a message
+ * @return Batch information
+ * @since 1.0
+ */
+ > T get(String batchId) throws ApiException;
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/SMSService.java b/client/src/main/com/sinch/sdk/domains/sms/SMSService.java
new file mode 100644
index 00000000..2947577e
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/SMSService.java
@@ -0,0 +1,19 @@
+package com.sinch.sdk.domains.sms;
+
+/**
+ * SMS Service
+ *
+ * @see https://developers.sinch.com/docs/sms/api-reference/
+ * @since 1.0
+ */
+public interface SMSService {
+
+ /**
+ * Batches Service instance
+ *
+ * @return service instance for project
+ * @since 1.0
+ */
+ BatchesService batches();
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/adapters/BatchesService.java b/client/src/main/com/sinch/sdk/domains/sms/adapters/BatchesService.java
new file mode 100644
index 00000000..c021da1e
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/adapters/BatchesService.java
@@ -0,0 +1,31 @@
+package com.sinch.sdk.domains.sms.adapters;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.core.http.HttpMapper;
+import com.sinch.sdk.domains.sms.adapters.api.v1.BatchesApi;
+import com.sinch.sdk.domains.sms.adapters.converters.BatchDtoConverter;
+import com.sinch.sdk.domains.sms.models.Batch;
+import com.sinch.sdk.models.Configuration;
+
+public class BatchesService implements com.sinch.sdk.domains.sms.BatchesService {
+
+ private Configuration configuration;
+ private BatchesApi api;
+
+ public BatchesService() {}
+
+ public BatchesService(Configuration configuration, HttpClient httpClient) {
+ this.configuration = configuration;
+ this.api = new BatchesApi(httpClient, configuration.getSmsServer(), new HttpMapper());
+ }
+
+ private BatchesApi getApi() {
+ return this.api;
+ }
+
+ public > T get(String batchId) throws ApiException {
+ return BatchDtoConverter.convert(
+ getApi().getBatchMessage(configuration.getProjectId(), batchId));
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java b/client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java
new file mode 100644
index 00000000..fd2f3a26
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/adapters/SMSService.java
@@ -0,0 +1,26 @@
+package com.sinch.sdk.domains.sms.adapters;
+
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.domains.sms.BatchesService;
+import com.sinch.sdk.models.Configuration;
+
+public class SMSService implements com.sinch.sdk.domains.sms.SMSService {
+
+ private final Configuration configuration;
+ private final HttpClient httpClient;
+ private BatchesService batches;
+
+ public SMSService(Configuration configuration, HttpClient httpClient) {
+ this.configuration = configuration;
+ this.httpClient = httpClient;
+ }
+
+ @Override
+ public BatchesService batches() {
+ if (null == this.batches) {
+ this.batches =
+ new com.sinch.sdk.domains.sms.adapters.BatchesService(configuration, httpClient);
+ }
+ return this.batches;
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/adapters/converters/BatchDtoConverter.java b/client/src/main/com/sinch/sdk/domains/sms/adapters/converters/BatchDtoConverter.java
new file mode 100644
index 00000000..d792241b
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/adapters/converters/BatchDtoConverter.java
@@ -0,0 +1,101 @@
+package com.sinch.sdk.domains.sms.adapters.converters;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.sms.models.*;
+import com.sinch.sdk.domains.sms.models.dto.v1.BinaryResponseDto;
+import com.sinch.sdk.domains.sms.models.dto.v1.MediaResponseDto;
+import com.sinch.sdk.domains.sms.models.dto.v1.SendSMS201ResponseDto;
+import com.sinch.sdk.domains.sms.models.dto.v1.TextResponseDto;
+
+public class BatchDtoConverter {
+
+ public static > T convert(SendSMS201ResponseDto dto) {
+ Object obj = dto.getActualInstance();
+ if (obj instanceof BinaryResponseDto) {
+ @SuppressWarnings("unchecked")
+ T t = (T) convertBinary(dto.getBinaryResponseDto());
+ return t;
+ } else if (obj instanceof MediaResponseDto) {
+ @SuppressWarnings("unchecked")
+ T t = (T) convertMedia(dto.getMediaResponseDto());
+ return t;
+ } else if (obj instanceof TextResponseDto) {
+ @SuppressWarnings("unchecked")
+ T t = (T) convertText(dto.getTextResponseDto());
+ return t;
+ } else {
+ throw new ApiException("Unexpected class:" + obj.getClass().getName());
+ }
+ }
+
+ private static BatchBinary convertBinary(BinaryResponseDto dto) {
+ return BatchBinary.builder()
+ .setId(dto.getId())
+ .setTo(dto.getTo())
+ .setFrom(dto.getFrom())
+ .setCanceled(dto.getCanceled())
+ .setBody(dto.getBody())
+ .setUdh(dto.getUdh())
+ .setCreatedAt(dto.getCreatedAt().toInstant())
+ .setModifiedAt(dto.getModifiedAt().toInstant())
+ .setDeliveryReport(DeliveryReport.from(dto.getDeliveryReport()))
+ .setSendAt(dto.getSendAt().toInstant())
+ .setExpireAt(dto.getExpireAt().toInstant())
+ .setCallbackUrl(dto.getCallbackUrl())
+ .setClientReference(dto.getClientReference())
+ .setFeedbackEnabled(dto.getFeedbackEnabled())
+ .setFlashMessage(dto.getFlashMessage())
+ .setTruncateConcat(dto.getTruncateConcat())
+ .setMaxNumberOfMessageParts(dto.getMaxNumberOfMessageParts())
+ .setFromTon(dto.getFromTon())
+ .setFromNpi(dto.getFromNpi())
+ .build();
+ }
+
+ private static BatchMedia convertMedia(MediaResponseDto dto) {
+ return BatchMedia.builder()
+ .setId(dto.getId())
+ .setTo(dto.getTo())
+ .setFrom(dto.getFrom())
+ .setCanceled(dto.getCanceled())
+ .setBody(
+ MediaBody.builder()
+ .setMessage(dto.getBody().getMessage())
+ .setUrl(dto.getBody().getUrl())
+ .build())
+ .setCreatedAt(dto.getCreatedAt().toInstant())
+ .setModifiedAt(dto.getModifiedAt().toInstant())
+ .setDeliveryReport(DeliveryReport.from(dto.getDeliveryReport()))
+ .setSendAt(dto.getSendAt().toInstant())
+ .setExpireAt(dto.getExpireAt().toInstant())
+ .setCallbackUrl(dto.getCallbackUrl())
+ .setClientReference(dto.getClientReference())
+ .setFeedbackEnabled(dto.getFeedbackEnabled())
+ .setParameters(ParametersDtoConverter.convert(dto.getParameters()))
+ .build();
+ }
+
+ private static BatchText convertText(TextResponseDto dto) {
+ return BatchText.builder()
+ .setId(dto.getId())
+ .setTo(dto.getTo())
+ .setFrom(dto.getFrom())
+ .setCanceled(dto.getCanceled())
+ .setBody(dto.getBody())
+ .setCreatedAt(dto.getCreatedAt().toInstant())
+ .setModifiedAt(dto.getModifiedAt().toInstant())
+ .setDeliveryReport(DeliveryReport.from(dto.getDeliveryReport()))
+ .setSendAt(dto.getSendAt().toInstant())
+ .setExpireAt(dto.getExpireAt().toInstant())
+ .setCallbackUrl(dto.getCallbackUrl())
+ .setClientReference(dto.getClientReference())
+ .setFeedbackEnabled(dto.getFeedbackEnabled())
+ .setFlashMessage(dto.getFlashMessage())
+ .setTruncateConcat(dto.getTruncateConcat())
+ .setMaxNumberOfMessageParts(dto.getMaxNumberOfMessageParts())
+ .setFromTon(dto.getFromTon())
+ .setFromNpi(dto.getFromNpi())
+ .setParameters(ParametersDtoConverter.convert(dto.getParameters()))
+ .build();
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/adapters/converters/ParametersDtoConverter.java b/client/src/main/com/sinch/sdk/domains/sms/adapters/converters/ParametersDtoConverter.java
new file mode 100644
index 00000000..1d4a2bd6
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/adapters/converters/ParametersDtoConverter.java
@@ -0,0 +1,46 @@
+package com.sinch.sdk.domains.sms.adapters.converters;
+
+import com.sinch.sdk.core.utils.Pair;
+import com.sinch.sdk.domains.sms.models.Parameters;
+import com.sinch.sdk.domains.sms.models.dto.v1.ParameterObjDto;
+import com.sinch.sdk.domains.sms.models.dto.v1.ParameterObjParameterKeyDto;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class ParametersDtoConverter {
+
+ public static Parameters convert(ParameterObjDto dto) {
+ return new Parameters(
+ dto.entrySet().stream()
+ .map(
+ entry -> {
+ @SuppressWarnings("unchecked")
+ Map entryValue = (Map) entry.getValue();
+ return new Parameters.Entry(
+ entry.getKey(),
+ entryValue.entrySet().stream()
+ .filter(
+ value ->
+ value
+ .getKey()
+ .compareTo(
+ ParameterObjParameterKeyDto.JSON_PROPERTY_DEFAULT)
+ != 0)
+ .map(e -> new Pair<>(e.getKey(), e.getValue()))
+ .findFirst()
+ .orElse(null),
+ entryValue.entrySet().stream()
+ .filter(
+ value ->
+ value
+ .getKey()
+ .compareTo(
+ ParameterObjParameterKeyDto.JSON_PROPERTY_DEFAULT)
+ == 0)
+ .map(Map.Entry::getValue)
+ .findFirst()
+ .orElse(null));
+ })
+ .collect(Collectors.toList()));
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/Batch.java b/client/src/main/com/sinch/sdk/domains/sms/models/Batch.java
new file mode 100644
index 00000000..9161adef
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/Batch.java
@@ -0,0 +1,303 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Collection;
+
+/**
+ * Base class for Batch types
+ *
+ * @param Type of batch
+ * @since 1.0
+ */
+public class Batch {
+
+ private final String id;
+
+ private final Collection to;
+
+ private final String from;
+
+ private final boolean canceled;
+
+ private final T body;
+
+ private final Instant createdAt;
+
+ private final Instant modifiedAt;
+
+ private final DeliveryReport deliveryReport;
+
+ private final Instant sendAt;
+
+ private final Instant expireAt;
+
+ private final String callbackUrl;
+
+ private final String clientReference;
+
+ private final boolean feedbackEnabled;
+
+ /**
+ * @param id Unique identifier for batch
+ * @param to List of Phone numbers and group IDs that will receive the batch
+ * @param from Sender number. Must be valid phone number, short code or alphanumeric. Required if
+ * Automatic Default Originator not configured.
+ * @param canceled Indicates if the batch has been canceled or not.
+ * @param body The message content
+ * @param createdAt when batch was created
+ * @param modifiedAt when batch was last updated
+ * @param deliveryReport Request delivery report callback. Note that delivery reports can be
+ * fetched from the API regardless of this setting
+ * @param sendAt If set in the future, the message will be delayed until send_at occurs. Must be
+ * before expire_at. If set in the past, messages will be sent immediately
+ * @param expireAt If set, the system will stop trying to deliver the message at this point. Must
+ * be after send_at. Default and max is 3 days after send_at
+ * @param callbackUrl Override the default callback URL for this batch. Must be valid URL.
+ * @param clientReference The client identifier of a batch message. If set, the identifier will be
+ * added in the delivery report/callback of this batch
+ * @param feedbackEnabled If set to true, then feedback is expected after successful delivery.
+ */
+ public Batch(
+ String id,
+ Collection to,
+ String from,
+ boolean canceled,
+ T body,
+ Instant createdAt,
+ Instant modifiedAt,
+ DeliveryReport deliveryReport,
+ Instant sendAt,
+ Instant expireAt,
+ String callbackUrl,
+ String clientReference,
+ boolean feedbackEnabled) {
+ this.id = id;
+ this.to = to;
+ this.from = from;
+ this.canceled = canceled;
+ this.body = body;
+ this.createdAt = createdAt;
+ this.modifiedAt = modifiedAt;
+ this.deliveryReport = deliveryReport;
+ this.sendAt = sendAt;
+ this.expireAt = expireAt;
+ this.callbackUrl = callbackUrl;
+ this.clientReference = clientReference;
+ this.feedbackEnabled = feedbackEnabled;
+ }
+
+ public static BatchBuilder batchBuilder() {
+ return new BatchBuilder<>();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public Collection getTo() {
+ return to;
+ }
+
+ public String getFrom() {
+ return from;
+ }
+
+ public boolean isCanceled() {
+ return canceled;
+ }
+
+ public T getBody() {
+ return body;
+ }
+
+ public Instant getCreatedAt() {
+ return createdAt;
+ }
+
+ public Instant getModifiedAt() {
+ return modifiedAt;
+ }
+
+ public DeliveryReport getDeliveryReport() {
+ return deliveryReport;
+ }
+
+ public Instant getSendAt() {
+ return sendAt;
+ }
+
+ public Instant getExpireAt() {
+ return expireAt;
+ }
+
+ public String getCallbackUrl() {
+ return callbackUrl;
+ }
+
+ public String getClientReference() {
+ return clientReference;
+ }
+
+ public boolean isFeedbackEnabled() {
+ return feedbackEnabled;
+ }
+
+ @Override
+ public String toString() {
+ return "Batch{"
+ + "id='"
+ + id
+ + '\''
+ + ", to="
+ + to
+ + ", from='"
+ + from
+ + '\''
+ + ", canceled="
+ + canceled
+ + ", body="
+ + body
+ + ", createdAt="
+ + createdAt
+ + ", modifiedAt="
+ + modifiedAt
+ + ", deliveryReport="
+ + deliveryReport
+ + ", sendAt="
+ + sendAt
+ + ", expireAt="
+ + expireAt
+ + ", callbackUrl='"
+ + callbackUrl
+ + '\''
+ + ", clientReference='"
+ + clientReference
+ + '\''
+ + ", feedbackEnabled="
+ + feedbackEnabled
+ + '}';
+ }
+
+ protected static class Builder> {
+
+ String id;
+
+ Collection to;
+
+ String from;
+
+ boolean canceled;
+
+ T body;
+
+ Instant createdAt;
+
+ Instant modifiedAt;
+
+ DeliveryReport deliveryReport;
+
+ Instant sendAt;
+
+ Instant expireAt;
+
+ String callbackUrl;
+
+ String clientReference;
+
+ boolean feedbackEnabled;
+
+ public B setId(String id) {
+ this.id = id;
+ return self();
+ }
+
+ public B setTo(Collection to) {
+ this.to = to;
+ return self();
+ }
+
+ public B setFrom(String from) {
+ this.from = from;
+ return self();
+ }
+
+ public B setCanceled(boolean canceled) {
+ this.canceled = canceled;
+ return self();
+ }
+
+ public B setBody(T body) {
+ this.body = body;
+ return self();
+ }
+
+ public B setCreatedAt(Instant createdAt) {
+ this.createdAt = createdAt;
+ return self();
+ }
+
+ public B setModifiedAt(Instant modifiedAt) {
+ this.modifiedAt = modifiedAt;
+ return self();
+ }
+
+ public B setDeliveryReport(DeliveryReport deliveryReport) {
+ this.deliveryReport = deliveryReport;
+ return self();
+ }
+
+ public B setSendAt(Instant sendAt) {
+ this.sendAt = sendAt;
+ return self();
+ }
+
+ public B setExpireAt(Instant expireAt) {
+ this.expireAt = expireAt;
+ return self();
+ }
+
+ public B setCallbackUrl(String callbackUrl) {
+ this.callbackUrl = callbackUrl;
+ return self();
+ }
+
+ public B setClientReference(String clientReference) {
+ this.clientReference = clientReference;
+ return self();
+ }
+
+ public B setFeedbackEnabled(boolean feedbackEnabled) {
+ this.feedbackEnabled = feedbackEnabled;
+ return self();
+ }
+
+ public Batch build() {
+ return new Batch<>(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected B self() {
+ return (B) this;
+ }
+ }
+
+ public static class BatchBuilder extends Batch.Builder> {
+ @Override
+ protected BatchBuilder self() {
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/BatchBinary.java b/client/src/main/com/sinch/sdk/domains/sms/models/BatchBinary.java
new file mode 100644
index 00000000..650da72d
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/BatchBinary.java
@@ -0,0 +1,204 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Collection;
+
+/**
+ * BatchBinary type
+ *
+ * @since 1.0
+ */
+public class BatchBinary extends Batch {
+ private final boolean flashMessage;
+ private final boolean truncateConcat;
+ private final int maxNumberOfMessageParts;
+ private final int fromTon;
+ private final int fromNpi;
+ private final String udh;
+
+ /**
+ * @param id Unique identifier for batch
+ * @param to List of Phone numbers and group IDs that will receive the batch
+ * @param from Sender number. Must be valid phone number, short code or alphanumeric. Required if
+ * Automatic Default Originator not configured.
+ * @param canceled Indicates if the batch has been canceled or not.
+ * @param body The message content
+ * @param createdAt when batch was created
+ * @param modifiedAt when batch was last updated
+ * @param deliveryReport Request delivery report callback. Note that delivery reports can be
+ * fetched from the API regardless of this setting
+ * @param sendAt If set in the future, the message will be delayed until send_at occurs. Must be
+ * before expire_at. If set in the past, messages will be sent immediately
+ * @param expireAt If set, the system will stop trying to deliver the message at this point. Must
+ * be after send_at. Default and max is 3 days after send_at
+ * @param callbackUrl Override the default callback URL for this batch. Must be valid URL.
+ * @param clientReference The client identifier of a batch message. If set, the identifier will be
+ * added in the delivery report/callback of this batch
+ * @param feedbackEnabled If set to true, then feedback is expected after successful delivery. *
+ * @param flashMessage If sent as a flash message, displays true.
+ * @param truncateConcat If set to true, the message was shortened when exceeding one part.
+ * @param maxNumberOfMessageParts Displays the number of message parts set in the request.
+ * @param fromTon The type of number for the sender number.
+ * @param fromNpi Number Plan Indicator for the sender number.
+ * @param udh The UDH header of a binary message HEX encoded. Max 140 bytes including the body.
+ */
+ public BatchBinary(
+ String id,
+ Collection to,
+ String from,
+ boolean canceled,
+ String body,
+ Instant createdAt,
+ Instant modifiedAt,
+ DeliveryReport deliveryReport,
+ Instant sendAt,
+ Instant expireAt,
+ String callbackUrl,
+ String clientReference,
+ boolean feedbackEnabled,
+ boolean flashMessage,
+ boolean truncateConcat,
+ int maxNumberOfMessageParts,
+ int fromTon,
+ int fromNpi,
+ String udh) {
+ super(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled);
+ this.flashMessage = flashMessage;
+ this.truncateConcat = truncateConcat;
+ this.maxNumberOfMessageParts = maxNumberOfMessageParts;
+ this.fromTon = fromTon;
+ this.fromNpi = fromNpi;
+ this.udh = udh;
+ }
+
+ public boolean isFlashMessage() {
+ return flashMessage;
+ }
+
+ public boolean isTruncateConcat() {
+ return truncateConcat;
+ }
+
+ public int getMaxNumberOfMessageParts() {
+ return maxNumberOfMessageParts;
+ }
+
+ public int getFromTon() {
+ return fromTon;
+ }
+
+ public int getFromNpi() {
+ return fromNpi;
+ }
+
+ public String getUdh() {
+ return udh;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "BatchBinary{"
+ + "flashMessage="
+ + flashMessage
+ + ", truncateConcat="
+ + truncateConcat
+ + ", maxNumberOfMessageParts="
+ + maxNumberOfMessageParts
+ + ", fromTon="
+ + fromTon
+ + ", fromNpi="
+ + fromNpi
+ + ", udh='"
+ + udh
+ + '\''
+ + "} "
+ + super.toString();
+ }
+
+ public static class Builder extends Batch.Builder {
+
+ private boolean flashMessage;
+ private boolean truncateConcat;
+ private int maxNumberOfMessageParts;
+ private int fromTon;
+ private int fromNpi;
+ private String udh;
+
+ private Builder() {}
+
+ public Builder setFlashMessage(boolean flashMessage) {
+ this.flashMessage = flashMessage;
+ return this;
+ }
+
+ public Builder setTruncateConcat(boolean truncateConcat) {
+ this.truncateConcat = truncateConcat;
+ return this;
+ }
+
+ public Builder setMaxNumberOfMessageParts(int maxNumberOfMessageParts) {
+ this.maxNumberOfMessageParts = maxNumberOfMessageParts;
+ return this;
+ }
+
+ public Builder setFromTon(int fromTon) {
+ this.fromTon = fromTon;
+ return this;
+ }
+
+ public Builder setFromNpi(int fromNpi) {
+ this.fromNpi = fromNpi;
+ return this;
+ }
+
+ public Builder setUdh(String udh) {
+ this.udh = udh;
+ return this;
+ }
+
+ public BatchBinary build() {
+ return new BatchBinary(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled,
+ flashMessage,
+ truncateConcat,
+ maxNumberOfMessageParts,
+ fromTon,
+ fromNpi,
+ udh);
+ }
+
+ @Override
+ protected Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/BatchMedia.java b/client/src/main/com/sinch/sdk/domains/sms/models/BatchMedia.java
new file mode 100644
index 00000000..75a02496
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/BatchMedia.java
@@ -0,0 +1,138 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Collection;
+
+/**
+ * BatchMedia type
+ *
+ * @since 1.0
+ */
+public class BatchMedia extends Batch {
+ private final Parameters parameters;
+ private final boolean strictValidation;
+
+ /**
+ * @param id Unique identifier for batch
+ * @param to List of Phone numbers and group IDs that will receive the batch
+ * @param from Sender number. Must be valid phone number, short code or alphanumeric. Required if
+ * Automatic Default Originator not configured.
+ * @param canceled Indicates if the batch has been canceled or not.
+ * @param body The message content
+ * @param createdAt when batch was created
+ * @param modifiedAt when batch was last updated
+ * @param deliveryReport Request delivery report callback. Note that delivery reports can be
+ * fetched from the API regardless of this setting
+ * @param sendAt If set in the future, the message will be delayed until send_at occurs. Must be
+ * before expire_at. If set in the past, messages will be sent immediately
+ * @param expireAt If set, the system will stop trying to deliver the message at this point. Must
+ * be after send_at. Default and max is 3 days after send_at
+ * @param callbackUrl Override the default callback URL for this batch. Must be valid URL.
+ * @param clientReference The client identifier of a batch message. If set, the identifier will be
+ * added in the delivery report/callback of this batch
+ * @param feedbackEnabled If set to true, then feedback is expected after successful delivery. *
+ * @param parameters Contains the parameters that will be used for customizing the message for
+ * each recipient.
+ * @param strictValidation Whether or not you want the media included in your message to be
+ * checked against Sinch MMS channel best practices. If set to true, your message will be
+ * rejected if it doesn't conform to the listed recommendations, otherwise no validation will
+ * be performed.
+ */
+ public BatchMedia(
+ String id,
+ Collection to,
+ String from,
+ boolean canceled,
+ MediaBody body,
+ Instant createdAt,
+ Instant modifiedAt,
+ DeliveryReport deliveryReport,
+ Instant sendAt,
+ Instant expireAt,
+ String callbackUrl,
+ String clientReference,
+ boolean feedbackEnabled,
+ Parameters parameters,
+ boolean strictValidation) {
+ super(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled);
+ this.parameters = parameters;
+ this.strictValidation = strictValidation;
+ }
+
+ public Parameters getParameters() {
+ return parameters;
+ }
+
+ public boolean isStrictValidation() {
+ return strictValidation;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public String toString() {
+ return "BatchMedia{"
+ + "parameters="
+ + parameters
+ + ", strictValidation="
+ + strictValidation
+ + "} "
+ + super.toString();
+ }
+
+ public static class Builder extends Batch.Builder {
+ private Parameters parameters;
+ private boolean strictValidation;
+
+ private Builder() {}
+
+ public Builder setParameters(Parameters parameters) {
+ this.parameters = parameters;
+ return this;
+ }
+
+ public Builder setStrictValidation(boolean strictValidation) {
+ this.strictValidation = strictValidation;
+ return this;
+ }
+
+ public BatchMedia build() {
+ return new BatchMedia(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled,
+ parameters,
+ strictValidation);
+ }
+
+ @Override
+ protected Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/BatchText.java b/client/src/main/com/sinch/sdk/domains/sms/models/BatchText.java
new file mode 100644
index 00000000..164a7366
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/BatchText.java
@@ -0,0 +1,203 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Collection;
+
+/**
+ * BatchText type
+ *
+ * @since 1.0
+ */
+public class BatchText extends Batch {
+ private final boolean flashMessage;
+ private final Parameters parameters;
+ private final boolean truncateConcat;
+ private final int maxNumberOfMessageParts;
+ private final int fromTon;
+ private final int fromNpi;
+
+ /**
+ * @param id Unique identifier for batch
+ * @param to List of Phone numbers and group IDs that will receive the batch
+ * @param from Sender number. Must be valid phone number, short code or alphanumeric. Required if
+ * Automatic Default Originator not configured.
+ * @param canceled Indicates if the batch has been canceled or not.
+ * @param body The message content
+ * @param createdAt when batch was created
+ * @param modifiedAt when batch was last updated
+ * @param deliveryReport Request delivery report callback. Note that delivery reports can be
+ * fetched from the API regardless of this setting
+ * @param sendAt If set in the future, the message will be delayed until send_at occurs. Must be
+ * before expire_at. If set in the past, messages will be sent immediately
+ * @param expireAt If set, the system will stop trying to deliver the message at this point. Must
+ * be after send_at. Default and max is 3 days after send_at
+ * @param callbackUrl Override the default callback URL for this batch. Must be valid URL.
+ * @param clientReference The client identifier of a batch message. If set, the identifier will be
+ * added in the delivery report/callback of this batch
+ * @param feedbackEnabled If set to true, then feedback is expected after successful delivery.
+ * @param parameters Contains the parameters that will be used for customizing the message for
+ * each recipient.
+ * @param flashMessage If sent as a flash message, displays true.
+ * @param truncateConcat If set to true, the message was shortened when exceeding one part.
+ * @param maxNumberOfMessageParts Displays the number of message parts set in the request.
+ * @param fromTon The type of number for the sender number.
+ * @param fromNpi Number Plan Indicator for the sender number.
+ */
+ public BatchText(
+ String id,
+ Collection to,
+ String from,
+ boolean canceled,
+ String body,
+ Instant createdAt,
+ Instant modifiedAt,
+ DeliveryReport deliveryReport,
+ Instant sendAt,
+ Instant expireAt,
+ String callbackUrl,
+ String clientReference,
+ boolean flashMessage,
+ boolean feedbackEnabled,
+ Parameters parameters,
+ boolean truncateConcat,
+ int maxNumberOfMessageParts,
+ int fromTon,
+ int fromNpi) {
+ super(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled);
+ this.flashMessage = flashMessage;
+ this.parameters = parameters;
+ this.truncateConcat = truncateConcat;
+ this.maxNumberOfMessageParts = maxNumberOfMessageParts;
+ this.fromTon = fromTon;
+ this.fromNpi = fromNpi;
+ }
+
+ public Parameters getParameters() {
+ return parameters;
+ }
+
+ public boolean isFlashMessage() {
+ return flashMessage;
+ }
+
+ public boolean isTruncateConcat() {
+ return truncateConcat;
+ }
+
+ public int getMaxNumberOfMessageParts() {
+ return maxNumberOfMessageParts;
+ }
+
+ public int getFromTon() {
+ return fromTon;
+ }
+
+ public int getFromNpi() {
+ return fromNpi;
+ }
+
+ @Override
+ public String toString() {
+ return "BatchText{"
+ + "flashMessage="
+ + flashMessage
+ + ", parameters="
+ + parameters
+ + ", truncateConcat="
+ + truncateConcat
+ + ", maxNumberOfMessageParts="
+ + maxNumberOfMessageParts
+ + ", fromTon="
+ + fromTon
+ + ", fromNpi="
+ + fromNpi
+ + "} "
+ + super.toString();
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends Batch.Builder {
+ private boolean flashMessage;
+ private Parameters parameters;
+ private boolean truncateConcat;
+ private int maxNumberOfMessageParts;
+ private int fromTon;
+ private int fromNpi;
+
+ private Builder() {}
+
+ public Builder setFlashMessage(boolean flashMessage) {
+ this.flashMessage = flashMessage;
+ return this;
+ }
+
+ public Builder setParameters(Parameters parameters) {
+ this.parameters = parameters;
+ return this;
+ }
+
+ public Builder setTruncateConcat(boolean truncateConcat) {
+ this.truncateConcat = truncateConcat;
+ return this;
+ }
+
+ public Builder setMaxNumberOfMessageParts(int maxNumberOfMessageParts) {
+ this.maxNumberOfMessageParts = maxNumberOfMessageParts;
+ return this;
+ }
+
+ public Builder setFromTon(int fromTon) {
+ this.fromTon = fromTon;
+ return this;
+ }
+
+ public Builder setFromNpi(int fromNpi) {
+ this.fromNpi = fromNpi;
+ return this;
+ }
+
+ public BatchText build() {
+ return new BatchText(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ flashMessage,
+ feedbackEnabled,
+ parameters,
+ truncateConcat,
+ maxNumberOfMessageParts,
+ fromTon,
+ fromNpi);
+ }
+
+ @Override
+ protected Builder self() {
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/DeliveryReport.java b/client/src/main/com/sinch/sdk/domains/sms/models/DeliveryReport.java
new file mode 100644
index 00000000..e706dafa
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/DeliveryReport.java
@@ -0,0 +1,60 @@
+package com.sinch.sdk.domains.sms.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * DeliveryReport authorized values
+ *
+ * @since 1.0
+ */
+public class DeliveryReport extends EnumDynamic {
+
+ /** No delivery report callback will be sent. */
+ public static final DeliveryReport NONE = new DeliveryReport("none");
+ /** A single delivery report callback will be sent. */
+ public static final DeliveryReport SUMMARY = new DeliveryReport("summary");
+ /**
+ * A single delivery report callback will be sent which includes a list of recipients per delivery
+ * status.
+ */
+ public static final DeliveryReport FULL = new DeliveryReport("full");
+ /**
+ * A delivery report callback will be sent for each status change of a message. This could result
+ * in a lot of callbacks and should be used with caution for larger batches. These delivery
+ * reports also include a timestamp of when the Delivery Report originated from the SMSC.
+ */
+ public static final DeliveryReport PER_RECIPIENT = new DeliveryReport("per_recipient");
+ /**
+ * A delivery report callback representing the final status of a message will be sent for each
+ * recipient. This will send only one callback per recipient, compared to the multiple callbacks
+ * sent when using per_recipient. The delivery report will also include a timestamp of when it
+ * originated from the SMSC.
+ */
+ public static final DeliveryReport PER_RECIPIENT_FINAl =
+ new DeliveryReport("per_recipient_final");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(
+ DeliveryReport.class,
+ DeliveryReport::new,
+ Arrays.asList(NONE, SUMMARY, FULL, PER_RECIPIENT, PER_RECIPIENT_FINAl));
+
+ private DeliveryReport(String value) {
+ super(value);
+ }
+
+ public static Stream values() {
+ return ENUM_SUPPORT.values();
+ }
+
+ public static DeliveryReport from(String value) {
+ return ENUM_SUPPORT.from(value);
+ }
+
+ public static String valueOf(DeliveryReport e) {
+ return ENUM_SUPPORT.valueOf(e);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/MediaBody.java b/client/src/main/com/sinch/sdk/domains/sms/models/MediaBody.java
new file mode 100644
index 00000000..acbc67ff
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/MediaBody.java
@@ -0,0 +1,59 @@
+package com.sinch.sdk.domains.sms.models;
+
+/**
+ * MediaBody object
+ *
+ * @since 1.0
+ */
+public class MediaBody {
+ private final String message;
+ private final String url;
+
+ /**
+ * @param url URL to the media file
+ * @param message The message text. Text only media messages will be rejected, please use SMS
+ * instead.
+ */
+ public MediaBody(String url, String message) {
+ this.message = message;
+ this.url = url;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ @Override
+ public String toString() {
+ return "MediaBody{" + "message='" + message + '\'' + ", url='" + url + '\'' + '}';
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String message;
+ private String url;
+
+ private Builder() {}
+
+ public Builder setMessage(String message) {
+ this.message = message;
+ return this;
+ }
+
+ public Builder setUrl(String url) {
+ this.url = url;
+ return this;
+ }
+
+ public MediaBody build() {
+ return new MediaBody(url, message);
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/models/Parameters.java b/client/src/main/com/sinch/sdk/domains/sms/models/Parameters.java
new file mode 100644
index 00000000..1921bb5a
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/models/Parameters.java
@@ -0,0 +1,55 @@
+package com.sinch.sdk.domains.sms.models;
+
+import com.sinch.sdk.core.utils.Pair;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class Parameters extends HashMap {
+
+ public Parameters(Collection list) {
+ super(list.stream().collect(Collectors.toMap(entry -> entry.key, entry -> entry)));
+ }
+
+ public static class Entry {
+ private final String key;
+ private final Pair value;
+ private final String defaultValue;
+
+ public Entry(String key, Pair value, String defaultValue) {
+ this.key = key;
+ this.value = value;
+ this.defaultValue = defaultValue;
+ }
+
+ public Entry(String key, Pair value) {
+ this(key, value, null);
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public Pair getValue() {
+ return value;
+ }
+
+ public Optional getDefaultValue() {
+ return Optional.ofNullable(defaultValue);
+ }
+
+ @Override
+ public String toString() {
+ return "Entry{"
+ + "key='"
+ + key
+ + '\''
+ + ", value="
+ + value
+ + ", defaultValue="
+ + defaultValue
+ + '}';
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/domains/sms/package-info.java b/client/src/main/com/sinch/sdk/domains/sms/package-info.java
new file mode 100644
index 00000000..dea88890
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/domains/sms/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * SMS API interface
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.domains.sms;
diff --git a/client/src/main/com/sinch/sdk/http/HttpClientApache.java b/client/src/main/com/sinch/sdk/http/HttpClientApache.java
new file mode 100644
index 00000000..588ff3f4
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/http/HttpClientApache.java
@@ -0,0 +1,209 @@
+package com.sinch.sdk.http;
+
+import static com.sinch.sdk.auth.adapters.BearerAuthManager.BEARER_AUTHENTICATE_RESPONSE_HEADER_KEYWORD;
+import static com.sinch.sdk.auth.adapters.BearerAuthManager.BEARER_EXPIRED_KEYWORD;
+import static com.sinch.sdk.core.http.URLParameterUtils.encodeParametersAsString;
+
+import com.sinch.sdk.auth.AuthManager;
+import com.sinch.sdk.auth.adapters.BearerAuthManager;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.http.*;
+import com.sinch.sdk.core.models.ServerConfiguration;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.logging.Logger;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.HttpEntity;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
+
+public class HttpClientApache implements com.sinch.sdk.core.http.HttpClient {
+ private static final Logger LOGGER = Logger.getLogger(HttpClientApache.class.getName());
+ private static final String AUTHORIZATION_HEADER_KEYWORD = "Authorization";
+ private final Map authManagers;
+ private CloseableHttpClient client;
+
+ public HttpClientApache(Map authManagers) {
+ this.client = HttpClients.createDefault();
+ this.authManagers = authManagers;
+ }
+
+ private static HttpResponse processResponse(ClassicHttpResponse response) throws IOException {
+
+ int statusCode = response.getCode();
+ Map> headers = transformResponseHeaders(response.getHeaders());
+ String message = response.getReasonPhrase();
+ LOGGER.finest("response: " + statusCode + ", headers:" + headers);
+
+ if (statusCode == org.apache.hc.core5.http.HttpStatus.SC_NO_CONTENT) {
+ return new HttpResponse(statusCode, message, headers, null);
+ }
+
+ HttpEntity entity = response.getEntity();
+ Scanner s = new Scanner(entity.getContent()).useDelimiter("\\A");
+ String content = (s.hasNext() ? s.next() : "");
+
+ return new HttpResponse(statusCode, message, headers, content.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private static Map> transformResponseHeaders(Header[] headers) {
+ Map> headersMap = new HashMap<>();
+ for (Header header : headers) {
+ List valuesList = headersMap.get(header.getName());
+ if (valuesList != null) {
+ valuesList.add(header.getValue());
+ } else {
+ valuesList = new ArrayList<>();
+ valuesList.add(header.getValue());
+ headersMap.put(header.getName(), valuesList);
+ }
+ }
+ return headersMap;
+ }
+
+ @Override
+ public HttpResponse invokeAPI(ServerConfiguration serverConfiguration, HttpRequest httpRequest)
+ throws ApiException {
+
+ try {
+ String path = serverConfiguration.getUrl() + httpRequest.getPath().orElse("");
+ HttpMethod method = httpRequest.getMethod();
+ Collection queryParameters = httpRequest.getQueryParameters();
+
+ String body = httpRequest.getBody();
+ Map headerParams = httpRequest.getHeaderParams();
+ Collection accept = httpRequest.getAccept();
+ Collection contentType = httpRequest.getContentType();
+ Collection authNames = httpRequest.getAuthNames();
+
+ LOGGER.fine("Invoke '" + method + "' onto '" + path + "'");
+ LOGGER.fine("queryParameters: " + queryParameters);
+ LOGGER.fine("body: " + body);
+ LOGGER.fine("headerParams: " + headerParams);
+ LOGGER.fine("accept: " + accept);
+ LOGGER.fine("contentType: " + contentType);
+ LOGGER.fine("authNames: " + authNames);
+
+ ClassicRequestBuilder requestBuilder = ClassicRequestBuilder.create(method.name());
+
+ setUri(requestBuilder, path, queryParameters);
+
+ addBody(requestBuilder, body);
+
+ addCollectionHeader(requestBuilder, "Content-Type", contentType);
+ addCollectionHeader(requestBuilder, "Accept", accept);
+
+ addAuth(requestBuilder, authNames);
+
+ ClassicHttpRequest request = requestBuilder.build();
+
+ HttpResponse response = processRequest(client, request);
+ LOGGER.finest("connection response: " + response);
+
+ // UNAUTHORIZED (HTTP 401) error code could imply refreshing the OAuth token
+ if (response.getCode() == HttpStatus.UNAUTHORIZED) {
+ boolean couldRetryRequest = processUnauthorizedResponse(httpRequest, response);
+ if (couldRetryRequest) {
+ // refresh authorization
+ addAuth(requestBuilder, authNames);
+ request = requestBuilder.build();
+ response = processRequest(client, request);
+ LOGGER.finest("connection response on retry: " + response);
+ }
+ }
+ return response;
+ } catch (Exception e) {
+ LOGGER.severe("Error:" + e);
+ throw new ApiException(e);
+ }
+ }
+
+ private boolean processUnauthorizedResponse(HttpRequest request, HttpResponse response) {
+
+ AuthManager bearerAuthManager = authManagers.get(BearerAuthManager.BEARER_SCHEMA_KEYWORD);
+ // is request was with Bearer authentication ?
+ Collection auths = request.getAuthNames();
+
+ if (null == bearerAuthManager || !auths.contains(BearerAuthManager.BEARER_SCHEMA_KEYWORD)) {
+ // not required to ask for a new token: original request is not using it
+ return false;
+ }
+ // looking for "expired" keyword present in "www-authenticate" header
+ Map> responseHeaders = response.getHeaders();
+ Collection header = responseHeaders.get(BEARER_AUTHENTICATE_RESPONSE_HEADER_KEYWORD);
+
+ boolean headerPresent = header.stream().anyMatch(e -> e.contains(BEARER_EXPIRED_KEYWORD));
+ if (headerPresent) {
+ bearerAuthManager.resetToken();
+ }
+ return headerPresent;
+ }
+
+ private void setUri(
+ ClassicRequestBuilder requestBuilder, String path, Collection parameters) {
+
+ if (null == parameters || parameters.isEmpty()) {
+ requestBuilder.setUri(path);
+ return;
+ }
+ String requestParameters = "?" + encodeParametersAsString(parameters);
+ LOGGER.finest("Request parameters: " + requestParameters);
+ requestBuilder.setUri(path + requestParameters);
+ }
+
+ private void addBody(ClassicRequestBuilder requestBuilder, String body) {
+ if (null != body) {
+ requestBuilder.setEntity(new StringEntity(body));
+ }
+ }
+
+ private void addCollectionHeader(
+ ClassicRequestBuilder requestBuilder, String header, Collection values) {
+ if (null != values && !values.isEmpty()) {
+ requestBuilder.setHeader(header, String.join(",", values));
+ }
+ }
+
+ private void addAuth(ClassicRequestBuilder requestBuilder, Collection values) {
+ if (null == values || values.isEmpty()) {
+ return;
+ }
+
+ for (String entry : values) {
+ if (authManagers.containsKey(entry)) {
+ AuthManager authManager = authManagers.get(entry);
+ requestBuilder.setHeader(
+ AUTHORIZATION_HEADER_KEYWORD, authManager.getAuthorizationHeaderValue());
+ return;
+ } else {
+ LOGGER.info("Ignore unknown authentication value: '" + entry + "'");
+ }
+ }
+ }
+
+ private HttpResponse processRequest(CloseableHttpClient client, ClassicHttpRequest request)
+ throws IOException {
+ return client.execute(request, HttpClientApache::processResponse);
+ }
+
+ @Override
+ public boolean isClosed() {
+ return null == client;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (!isClosed()) {
+ try {
+ client.close();
+ } finally {
+ client = null;
+ }
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/models/Configuration.java b/client/src/main/com/sinch/sdk/models/Configuration.java
new file mode 100644
index 00000000..dae0b99b
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/models/Configuration.java
@@ -0,0 +1,292 @@
+package com.sinch.sdk.models;
+
+import com.sinch.sdk.core.models.ServerConfiguration;
+
+/** Configuration used by Sinch Client */
+public class Configuration {
+
+ private final String keyId;
+ private final String keySecret;
+ private final String projectId;
+ private final String oauthUrl;
+ private final String numbersUrl;
+ private final SMSRegion smsRegion;
+ private final String smsUrl;
+
+ private Configuration(
+ String keyId,
+ String keySecret,
+ String projectId,
+ String oauthUrl,
+ String numbersUrl,
+ SMSRegion smsRegion,
+ String smsUrl) {
+ this.keyId = keyId;
+ this.keySecret = keySecret;
+ this.projectId = projectId;
+ this.oauthUrl = oauthUrl;
+ this.numbersUrl = numbersUrl;
+ this.smsRegion = null == smsRegion ? SMSRegion.US : smsRegion;
+ this.smsUrl = smsUrl;
+ }
+
+ @Override
+ public String toString() {
+ // ! do not dump secret values
+ return "Configuration{"
+ + "keyId=..."
+ + ", keySecret=..."
+ + ", projectId=..."
+ + ", oAuthUrl='"
+ + oauthUrl
+ + '\''
+ + ", numbersUrl='"
+ + numbersUrl
+ + '\''
+ + ", smsRegion='"
+ + smsRegion
+ + '\''
+ + ", smsUrl='"
+ + smsUrl
+ + '\''
+ + "}";
+ }
+
+ /**
+ * Get Key ID
+ *
+ * @return key id.
+ * @see https://developers.sinch.com/
+ * @since 1.0
+ */
+ public String getKeyId() {
+ return keyId;
+ }
+
+ /**
+ * Get key ID
+ *
+ * @return key secret.
+ * @see https://developers.sinch.com/
+ * @since 1.0
+ */
+ public String getKeySecret() {
+ return keySecret;
+ }
+
+ /**
+ * Get Project ID
+ *
+ * @return Project id.
+ * @see https://developers.sinch.com/
+ * @since 1.0
+ */
+ public String getProjectId() {
+ return projectId;
+ }
+
+ /**
+ * OAuth server
+ *
+ * @return OAuth Server configuration to be used
+ * @since 1.0
+ */
+ public ServerConfiguration getOAuthServer() {
+ return new ServerConfiguration(getOAuthUrl());
+ }
+
+ /**
+ * OAuth URL
+ *
+ * @return OAuth Server URL
+ * @since 1.0
+ */
+ public String getOAuthUrl() {
+ return oauthUrl;
+ }
+
+ /**
+ * Numbers Server Configuration
+ *
+ * @return Numbers Server configuration to be used
+ * @since 1.0
+ */
+ public ServerConfiguration getNumbersServer() {
+ return new ServerConfiguration(getNumbersUrl());
+ }
+
+ /**
+ * Numbers URL
+ *
+ * @return Numbers Server URL
+ * @since 1.0
+ */
+ public String getNumbersUrl() {
+ return numbersUrl;
+ }
+
+ /**
+ * SMS Server Configuration
+ *
+ * @return SMS Server configuration to be used
+ * @since 1.0
+ */
+ public ServerConfiguration getSmsServer() {
+ return new ServerConfiguration(String.format(getSmsUrl(), getSmsRegion()));
+ }
+
+ /**
+ * SMS Region
+ *
+ * @return SMS region
+ * @see https://developers.sinch.com/docs/sms/api-reference/#base-url/
+ * @since 1.0
+ */
+ public SMSRegion getSmsRegion() {
+ return smsRegion;
+ }
+
+ /**
+ * SMS URL
+ *
+ * @return SMS Server URL
+ * @since 1.0
+ */
+ public String getSmsUrl() {
+ return smsUrl;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Builder builder(Configuration configuration) {
+ return new Builder(configuration);
+ }
+
+ /** Configuration builder */
+ public static class Builder {
+
+ private String keyId;
+ private String keySecret;
+ private String projectId;
+ private String oauthUrl;
+ private String numbersUrl;
+ private SMSRegion smsRegion;
+ private String smsUrl;
+
+ protected Builder() {}
+
+ /**
+ * Initialize a builder with existing configuration
+ *
+ * @param configuration Configuration to be used as initial builder state
+ * @since 1.0
+ */
+ protected Builder(Configuration configuration) {
+ this.keyId = configuration.getKeyId();
+ this.keySecret = configuration.getKeySecret();
+ this.projectId = configuration.getProjectId();
+ this.oauthUrl = configuration.getOAuthUrl();
+ this.numbersUrl = configuration.getNumbersUrl();
+ this.smsRegion = configuration.getSmsRegion();
+ this.smsUrl = configuration.getSmsUrl();
+ }
+
+ /**
+ * Build a Configuration instance from builder current state
+ *
+ * @return Configuration instance build from current builder state
+ * @since 1.0
+ */
+ public Configuration build() {
+ return new Configuration(
+ keyId, keySecret, projectId, oauthUrl, numbersUrl, smsRegion, smsUrl);
+ }
+
+ /**
+ * Set key ID
+ *
+ * @param keyId key ID
+ * @return Current builder
+ * @since 1.0
+ */
+ public Builder setKeyId(String keyId) {
+ this.keyId = keyId;
+ return this;
+ }
+
+ /**
+ * Set key secret
+ *
+ * @param keySecret key secret
+ * @return Current builder
+ * @since 1.0
+ */
+ public Builder setKeySecret(String keySecret) {
+ this.keySecret = keySecret;
+ return this;
+ }
+
+ /**
+ * Set Project ID
+ *
+ * @param projectId Project ID
+ * @return Current builder
+ * @since 1.0
+ */
+ public Builder setProjectId(String projectId) {
+ this.projectId = projectId;
+ return this;
+ }
+
+ /**
+ * Set OAuth URL
+ *
+ * @param oauthUrl OAuth URL
+ * @return Current builder
+ * @since 1.0
+ */
+ public Builder setOAuthUrl(String oauthUrl) {
+ this.oauthUrl = oauthUrl;
+ return this;
+ }
+
+ /**
+ * Set Numbers API URL
+ *
+ * @param numbersUrl Numbers API URL
+ * @return Current builder
+ * @since 1.0
+ */
+ public Builder setNumbersUrl(String numbersUrl) {
+ this.numbersUrl = numbersUrl;
+ return this;
+ }
+
+ /**
+ * Set SMS region
+ *
+ * @param smsRegion SMS region
+ * @return Current builder
+ * @since 1.0
+ */
+ public Builder setSmsRegion(SMSRegion smsRegion) {
+ this.smsRegion = smsRegion;
+ return this;
+ }
+
+ /**
+ * Set SMS API URL
+ *
+ * @param smsUrl SMS API URL
+ * @return Current builder
+ * @since 1.0
+ */
+ public Builder setSmsUrl(String smsUrl) {
+ this.smsUrl = smsUrl;
+ return this;
+ }
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/models/SMSRegion.java b/client/src/main/com/sinch/sdk/models/SMSRegion.java
new file mode 100644
index 00000000..c198f604
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/models/SMSRegion.java
@@ -0,0 +1,67 @@
+package com.sinch.sdk.models;
+
+import com.sinch.sdk.core.utils.EnumDynamic;
+import com.sinch.sdk.core.utils.EnumSupportDynamic;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+/**
+ * SMS Region
+ *
+ * Available SMS region Regions are tied to a specific SMS API URL
+ *
+ * @see https://developers.sinch.com/docs/sms/api-reference/#base-url/
+ * @since 1.0
+ */
+public class SMSRegion extends EnumDynamic {
+
+ /** United States */
+ public static final SMSRegion US = new SMSRegion("us");
+
+ /** European Union */
+ public static final SMSRegion EU = new SMSRegion("eu");
+ /** Australia */
+ public static final SMSRegion AU = new SMSRegion("au");
+ /** Brazil */
+ public static final SMSRegion BR = new SMSRegion("br");
+ /** Canada */
+ public static final SMSRegion CA = new SMSRegion("ca");
+
+ private static final EnumSupportDynamic ENUM_SUPPORT =
+ new EnumSupportDynamic<>(SMSRegion.class, SMSRegion::new, Arrays.asList(US, EU, AU, BR, CA));
+
+ private SMSRegion(String value) {
+ super(value);
+ }
+
+ /**
+ * Get list of regions
+ *
+ * @return List of known SMS region
+ */
+ public static Stream values() {
+ return ENUM_SUPPORT.values();
+ }
+
+ /**
+ * Get SMS region from a String
+ *
+ * @param value String region identifier. Create an SMS Region instance if not known at
+ * compilation
+ * @return SMSRegion identified by the string
+ */
+ public static SMSRegion from(String value) {
+ return ENUM_SUPPORT.from(value);
+ }
+
+ /**
+ * Get SMS region string identifier
+ *
+ * @param value region identifier
+ * @return String value identifier for region
+ */
+ public static String valueOf(SMSRegion value) {
+ return ENUM_SUPPORT.valueOf(value);
+ }
+}
diff --git a/client/src/main/com/sinch/sdk/models/package-info.java b/client/src/main/com/sinch/sdk/models/package-info.java
new file mode 100644
index 00000000..0533af6d
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/models/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Common models in use with Sinch Client Library
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.models;
diff --git a/client/src/main/com/sinch/sdk/package-info.java b/client/src/main/com/sinch/sdk/package-info.java
new file mode 100644
index 00000000..1da0e66f
--- /dev/null
+++ b/client/src/main/com/sinch/sdk/package-info.java
@@ -0,0 +1,16 @@
+/**
+ * Sinch Java SDK for Numbers & SMS
+ *
+ * Provides the client necessary to interface with Sinch APIS
+ *
+ *
The client involve different layers:
+ *
+ *
+ * - configuration with unified identifier to connect to APIS
+ *
- client handling underline communication with APIS
+ *
+ *
+ * @see https://developers.sinch.com/
+ * @since 1.0
+ */
+package com.sinch.sdk;
diff --git a/client/src/test/java/com/sinch/sdk/SinchClientTest.java b/client/src/test/java/com/sinch/sdk/SinchClientTest.java
new file mode 100644
index 00000000..693ac834
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/SinchClientTest.java
@@ -0,0 +1,60 @@
+package com.sinch.sdk;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.sinch.sdk.models.Configuration;
+import org.junit.jupiter.api.Test;
+
+class SinchClientTest {
+
+ @Test
+ void doNotAcceptNullKey() {
+ Configuration configuration =
+ Configuration.builder().setKeyId(null).setKeySecret("foo").setProjectId("foo").build();
+ Exception exception =
+ assertThrows(NullPointerException.class, () -> new SinchClient(configuration));
+ assertTrue(exception.getMessage().contains("keyId"));
+ }
+
+ @Test
+ void doNotAcceptNullKeySecret() {
+ Configuration configuration =
+ Configuration.builder().setKeyId("foo").setKeySecret(null).setProjectId("foo").build();
+ Exception exception =
+ assertThrows(NullPointerException.class, () -> new SinchClient(configuration));
+ assertTrue(exception.getMessage().contains("keySecret"));
+ }
+
+ @Test
+ void doNotAcceptNullProject() {
+ Configuration configuration =
+ Configuration.builder().setKeyId("foo").setKeySecret("foo").setProjectId(null).build();
+ Exception exception =
+ assertThrows(NullPointerException.class, () -> new SinchClient(configuration));
+ assertTrue(exception.getMessage().contains("projectId"));
+ }
+
+ @Test
+ void defaultOAuthUrlAvailable() {
+ Configuration configuration =
+ Configuration.builder().setKeyId("foo").setKeySecret("foo").setProjectId("foo").build();
+ SinchClient client = new SinchClient(configuration);
+ assertNotNull(client.getConfiguration().getOAuthUrl());
+ }
+
+ @Test
+ void defaultNumbersUrlAvailable() {
+ Configuration configuration =
+ Configuration.builder().setKeyId("foo").setKeySecret("foo").setProjectId("foo").build();
+ SinchClient client = new SinchClient(configuration);
+ assertNotNull(client.getConfiguration().getNumbersUrl());
+ }
+
+ @Test
+ void defaultSmsUrlAvailable() {
+ Configuration configuration =
+ Configuration.builder().setKeyId("foo").setKeySecret("foo").setProjectId("foo").build();
+ SinchClient client = new SinchClient(configuration);
+ assertNotNull(client.getConfiguration().getSmsUrl());
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/auth/adapters/BasicAuthManagerTest.java b/client/src/test/java/com/sinch/sdk/auth/adapters/BasicAuthManagerTest.java
new file mode 100644
index 00000000..b0269728
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/auth/adapters/BasicAuthManagerTest.java
@@ -0,0 +1,38 @@
+package com.sinch.sdk.auth.adapters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.auth.AuthManager;
+import com.sinch.sdk.models.Configuration;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import org.junit.jupiter.api.Test;
+
+class BasicAuthManagerTest {
+
+ static final String KEY = "fooKey";
+ static final String SECRET = "fooSecret";
+ static final String PROJECT = "fooProject";
+
+ Configuration configuration =
+ Configuration.builder().setKeyId(KEY).setKeySecret(SECRET).setProjectId(PROJECT).build();
+
+ AuthManager authManager = new BasicAuthManager(configuration);
+
+ @Test
+ void getSchema() {
+ assertEquals("BasicAuth", authManager.getSchema());
+ }
+
+ @Test
+ void getAuthorizationHeaderValue() {
+
+ String expectedToken =
+ "Basic "
+ + Base64.getEncoder()
+ .encodeToString(
+ (configuration.getKeyId() + ":" + configuration.getKeySecret())
+ .getBytes(StandardCharsets.UTF_8));
+ assertEquals(expectedToken, authManager.getAuthorizationHeaderValue());
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/auth/adapters/BearerAuthManagerTest.java b/client/src/test/java/com/sinch/sdk/auth/adapters/BearerAuthManagerTest.java
new file mode 100644
index 00000000..3584ffc8
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/auth/adapters/BearerAuthManagerTest.java
@@ -0,0 +1,111 @@
+package com.sinch.sdk.auth.adapters;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import com.adelean.inject.resources.junit.jupiter.GivenTextResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.auth.AuthManager;
+import com.sinch.sdk.core.exceptions.ApiAuthException;
+import com.sinch.sdk.core.http.HttpClient;
+import com.sinch.sdk.core.http.HttpMapper;
+import com.sinch.sdk.core.http.HttpMethod;
+import com.sinch.sdk.core.http.HttpRequest;
+import com.sinch.sdk.core.http.HttpResponse;
+import com.sinch.sdk.core.models.ServerConfiguration;
+import com.sinch.sdk.models.Configuration;
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+@TestWithResources
+public class BearerAuthManagerTest extends BaseTest {
+ static final String KEY = "fooKey";
+ static final String SECRET = "fooSecret";
+ static final String PROJECT = "fooProject";
+
+ @GivenTextResource("/client/auth/BearerAuthResponse.json")
+ String jsonResponse;
+
+ @Mock HttpClient httpClient;
+ @Captor ArgumentCaptor serverConfigurationCaptor;
+ @Captor ArgumentCaptor httpRequestCaptor;
+ Configuration configuration =
+ Configuration.builder()
+ .setKeyId(KEY)
+ .setKeySecret(SECRET)
+ .setProjectId(PROJECT)
+ .setOAuthUrl("OAuth url")
+ .build();
+
+ AuthManager authManager = new BearerAuthManager(configuration, new HttpMapper());
+
+ @Test
+ void getSchema() {
+ assertEquals("BearerAuth", authManager.getSchema());
+ }
+
+ @Test
+ void getAuthorizationHeaderValue() {
+ String expectedToken = "Bearer token value";
+
+ when(httpClient.invokeAPI(any(), any()))
+ .thenReturn(
+ new HttpResponse(
+ 200, "foo message", null, jsonResponse.getBytes(StandardCharsets.UTF_8)));
+ authManager.setHttpClient(httpClient);
+
+ String token = authManager.getAuthorizationHeaderValue();
+
+ assertEquals(expectedToken, token);
+ }
+
+ @Test
+ void callToOAuthServer() {
+ when(httpClient.invokeAPI(serverConfigurationCaptor.capture(), httpRequestCaptor.capture()))
+ .thenReturn(
+ new HttpResponse(
+ 200, "foo message", null, jsonResponse.getBytes(StandardCharsets.UTF_8)));
+ authManager.setHttpClient(httpClient);
+
+ authManager.getAuthorizationHeaderValue();
+
+ ServerConfiguration serverConfigurationValue = serverConfigurationCaptor.getValue();
+ assertEquals("OAuth url", serverConfigurationValue.getUrl());
+
+ HttpRequest httpRequestCaptorValue = httpRequestCaptor.getValue();
+ assertEquals(HttpMethod.POST, httpRequestCaptorValue.getMethod());
+ assertTrue(httpRequestCaptorValue.getAuthNames().stream().anyMatch(e -> e.equals("BasicAuth")));
+ assertTrue(
+ httpRequestCaptorValue.getContentType().stream()
+ .anyMatch(e -> e.equals("application/x-www-form-urlencoded")));
+ assertEquals("grant_type=client_credentials", httpRequestCaptorValue.getBody());
+ }
+
+ @Test
+ void resetToken() {
+ when(httpClient.invokeAPI(any(), any()))
+ .thenReturn(
+ new HttpResponse(
+ 200, "foo message", null, jsonResponse.getBytes(StandardCharsets.UTF_8)));
+ authManager.setHttpClient(httpClient);
+
+ authManager.resetToken();
+ authManager.getAuthorizationHeaderValue();
+
+ verify(httpClient, times(1)).invokeAPI(any(), any());
+ }
+
+ @Test
+ void noInfiniteLoopAndException() {
+ authManager.setHttpClient(httpClient);
+
+ ApiAuthException exception =
+ assertThrows(ApiAuthException.class, authManager::getAuthorizationHeaderValue);
+ assertEquals(exception.getCode(), 401);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/auth/models/BearerAuthResponseTest.java b/client/src/test/java/com/sinch/sdk/auth/models/BearerAuthResponseTest.java
new file mode 100644
index 00000000..24800fd0
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/auth/models/BearerAuthResponseTest.java
@@ -0,0 +1,43 @@
+package com.sinch.sdk.auth.models;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import org.junit.jupiter.api.Test;
+
+@TestWithResources
+public class BearerAuthResponseTest extends BaseTest {
+
+ static final String token = "token value";
+
+ @GivenJsonResource("/client/auth/BearerAuthResponse.json")
+ BearerAuthResponse response;
+
+ @Test
+ void getAccessToken() {
+ assertEquals(token, response.getAccessToken());
+ }
+
+ @Test
+ void getExpiresIn() {
+ assertEquals(123456, response.getExpiresIn());
+ }
+
+ @Test
+ void getScope() {
+ assertEquals("scope value", response.getScope());
+ }
+
+ @Test
+ void getTokenType() {
+ assertEquals("token type value", response.getTokenType());
+ }
+
+ @Test
+ void to_String() {
+ assertFalse(response.toString().contains(token));
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/core/adapters/apache/HttpClientTestIT.java b/client/src/test/java/com/sinch/sdk/core/adapters/apache/HttpClientTestIT.java
new file mode 100644
index 00000000..20e94b60
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/core/adapters/apache/HttpClientTestIT.java
@@ -0,0 +1,180 @@
+package com.sinch.sdk.core.adapters.apache;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.adelean.inject.resources.junit.jupiter.GivenTextResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.auth.AuthManager;
+import com.sinch.sdk.auth.adapters.BasicAuthManager;
+import com.sinch.sdk.auth.adapters.BearerAuthManager;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.http.HttpMapper;
+import com.sinch.sdk.core.http.HttpMethod;
+import com.sinch.sdk.core.http.HttpRequest;
+import com.sinch.sdk.core.http.HttpStatus;
+import com.sinch.sdk.core.models.ServerConfiguration;
+import com.sinch.sdk.http.HttpClientApache;
+import com.sinch.sdk.models.Configuration;
+import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import okhttp3.mockwebserver.RecordedRequest;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+@TestWithResources
+class HttpClientTestIT extends BaseTest {
+ static MockWebServer mockBackEnd;
+
+ @GivenTextResource("/client/auth/BearerAuthResponse.json")
+ String jsonResponse;
+
+ String serverUrl = String.format("http://localhost:%s", mockBackEnd.getPort());
+ Configuration configuration =
+ Configuration.builder().setOAuthUrl(String.format("%s/auth", serverUrl)).build();
+
+ AuthManager basicAuthManager = new BasicAuthManager(configuration);
+ BearerAuthManager bearerAuthManager = new BearerAuthManager(configuration, new HttpMapper());
+
+ Map authManagers =
+ Stream.of(basicAuthManager, bearerAuthManager)
+ .map(e -> new AbstractMap.SimpleEntry<>(e.getSchema(), e))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+ HttpClientApache httpClient = new HttpClientApache(authManagers);
+
+ @BeforeAll
+ static void classSetUp() throws IOException {
+ mockBackEnd = new MockWebServer();
+ mockBackEnd.start();
+ }
+
+ @AfterAll
+ static void tearDown() throws IOException {
+ mockBackEnd.shutdown();
+ }
+
+ @BeforeEach
+ void testSetUp() {
+ bearerAuthManager.setHttpClient(httpClient);
+ }
+
+ @Test
+ void basicAuthorization() throws InterruptedException {
+
+ mockBackEnd.enqueue(
+ new MockResponse().setBody("foo").addHeader("Content-Type", "application/json"));
+ httpClient.invokeAPI(
+ new ServerConfiguration(String.format("%s/foo", serverUrl)),
+ new HttpRequest(
+ "foo-path",
+ HttpMethod.GET,
+ null,
+ null,
+ null,
+ null,
+ null,
+ Collections.singletonList(BasicAuthManager.BASIC_SCHEMA_KEYWORD)));
+ RecordedRequest recordedRequest = mockBackEnd.takeRequest();
+
+ String header = recordedRequest.getHeader("Authorization");
+
+ assertTrue(header.startsWith("Basic "));
+ }
+
+ @Test
+ void initialBearerAuthorization() throws InterruptedException {
+ mockBackEnd.enqueue(
+ new MockResponse().setBody(jsonResponse).addHeader("Content-Type", "application/json"));
+ mockBackEnd.enqueue(
+ new MockResponse().setBody("foo3").addHeader("Content-Type", "application/json"));
+ httpClient.invokeAPI(
+ new ServerConfiguration(String.format("%s/foo", serverUrl)),
+ new HttpRequest(
+ "foo-path",
+ HttpMethod.GET,
+ null,
+ null,
+ null,
+ null,
+ null,
+ Collections.singletonList(BearerAuthManager.BEARER_SCHEMA_KEYWORD)));
+
+ RecordedRequest recordedRequest = mockBackEnd.takeRequest();
+
+ String header = recordedRequest.getHeader("Authorization");
+ assertTrue(header.startsWith("Basic "));
+ assertEquals("/auth", recordedRequest.getPath());
+ // unused for this test: but to flush mocked backend request stack and avoid cross tests issue
+ mockBackEnd.takeRequest();
+ }
+
+ @Test
+ void bearerAutoRefresh() throws InterruptedException {
+ // return valid token
+ mockBackEnd.enqueue(
+ new MockResponse().setBody(jsonResponse).addHeader("Content-Type", "application/json"));
+ // return unauthorized
+ mockBackEnd.enqueue(
+ new MockResponse()
+ .setResponseCode(HttpStatus.UNAUTHORIZED)
+ .setBody("foo2")
+ .addHeader("www-authenticate", "token invalid: expired")
+ .addHeader("Content-Type", "application/json"));
+ // return valid token
+ mockBackEnd.enqueue(
+ new MockResponse()
+ .setBody(jsonResponse.replace("token value", "another token"))
+ .addHeader("Content-Type", "application/json"));
+ // return a body
+ mockBackEnd.enqueue(
+ new MockResponse().setBody("foo3").addHeader("Content-Type", "application/json"));
+ try {
+ httpClient.invokeAPI(
+ new ServerConfiguration(String.format("%s/foo/", serverUrl)),
+ new HttpRequest(
+ "foo-path",
+ HttpMethod.GET,
+ null,
+ null,
+ null,
+ null,
+ null,
+ Collections.singletonList(BearerAuthManager.BEARER_SCHEMA_KEYWORD)));
+ } catch (ApiException ae) {
+ // noop
+ }
+ // should have requested a token (because of not yet retrieved when service is started)
+ RecordedRequest recordedRequest = mockBackEnd.takeRequest();
+ assertEquals("/auth", recordedRequest.getPath());
+ String header = recordedRequest.getHeader("Authorization");
+ // auth is using Basic authentication
+ assertTrue(header.startsWith("Basic "));
+
+ // should have requested the original endpoint but with a token now
+ recordedRequest = mockBackEnd.takeRequest();
+ assertEquals("/foo/foo-path", recordedRequest.getPath());
+ header = recordedRequest.getHeader("Authorization");
+ assertEquals(header, "Bearer token value");
+
+ // should have requested another token because the second request triggered an "expired" one
+ recordedRequest = mockBackEnd.takeRequest();
+ assertEquals("/auth", recordedRequest.getPath());
+ header = recordedRequest.getHeader("Authorization");
+ assertTrue(header.startsWith("Basic "));
+
+ recordedRequest = mockBackEnd.takeRequest();
+ assertEquals("/foo/foo-path", recordedRequest.getPath());
+ header = recordedRequest.getHeader("Authorization");
+ assertEquals(header, "Bearer another token");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/ActiveNumberServiceTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/ActiveNumberServiceTest.java
new file mode 100644
index 00000000..5d16f105
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/ActiveNumberServiceTest.java
@@ -0,0 +1,335 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.models.pagination.Page;
+import com.sinch.sdk.core.models.pagination.PageToken;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.ActiveNumberApi;
+import com.sinch.sdk.domains.numbers.adapters.converters.ActiveNumberUpdateRequestParametersDtoConverter;
+import com.sinch.sdk.domains.numbers.models.*;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumbersResponseDto;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberListRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateSMSConfigurationRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateVoiceConfigurationRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.ActiveNumberListResponse;
+import com.sinch.sdk.models.Configuration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collections;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatchers;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+@TestWithResources
+class ActiveNumberServiceTest extends BaseTest {
+
+ @GivenJsonResource("/domains/numbers/v1/active-numbers-list-light.json")
+ ActiveNumbersResponseDto activeNumbersListLightDto;
+
+ @GivenJsonResource("/domains/numbers/v1/active-numbers-list.json")
+ ActiveNumbersResponseDto activeNumbersListDto;
+
+ @GivenJsonResource("/domains/numbers/v1/active-numbers-get.json")
+ ActiveNumberDto activeGetResponseDto;
+
+ @Mock Configuration configuration;
+ @Mock ActiveNumberApi api;
+ @InjectMocks ActiveNumberService service;
+
+ @Test
+ void list() throws ApiException {
+
+ when(api.numberServiceListActiveNumbers(
+ eq(configuration.getProjectId()),
+ eq("region"),
+ eq(NumberType.MOBILE.value()),
+ eq(null),
+ eq(null),
+ eq(null),
+ eq(null),
+ eq(null),
+ eq(null)))
+ .thenReturn(activeNumbersListLightDto);
+
+ ActiveNumberListResponse response =
+ service.list(
+ ActiveNumberListRequestParameters.builder()
+ .setRegionCode("region")
+ .setType(NumberType.MOBILE)
+ .build());
+
+ Page expected =
+ new Page<>(
+ ActiveNumberListRequestParameters.builder()
+ .setRegionCode("region")
+ .setType(NumberType.MOBILE)
+ .build(),
+ Collections.singletonList(
+ ActiveNumber.builder()
+ .setPhoneNumber("+447520651116XYZ")
+ .setProjectId("project id")
+ .setRegionCode("GB")
+ .setType(NumberType.MOBILE)
+ .setCapability(Arrays.asList(Capability.SMS, Capability.VOICE))
+ .setDisplayName("")
+ .setMoney(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setNextChargeDate(Instant.parse("2023-09-22T15:49:58.813424Z"))
+ .setExpireAt(Instant.parse("2023-10-06T15:49:58.813381Z"))
+ .setSmsConfiguration(new SMSConfiguration("service plan id", "", null))
+ .setVoiceConfiguration(new VoiceConfiguration("app id", null, null))
+ .setCallbackUrl("")
+ .build()),
+ new PageToken<>(""));
+ Assertions.assertThat(response.getContent())
+ .usingRecursiveComparison()
+ .isEqualTo(expected.getEntities());
+ }
+
+ @Test
+ void listWithParameters() throws ApiException {
+
+ when(api.numberServiceListActiveNumbers(
+ eq(configuration.getProjectId()),
+ eq("another region"),
+ eq(NumberType.TOLL_FREE.value()),
+ eq("pattern value"),
+ eq(SearchPattern.END.value()),
+ eq(Collections.singletonList(Capability.VOICE.value())),
+ eq(5),
+ eq("foo"),
+ eq(OrderBy.PHONE_NUMBER.value())))
+ .thenReturn(activeNumbersListDto);
+
+ ActiveNumberListRequestParameters parameters =
+ ActiveNumberListRequestParameters.builder()
+ .setRegionCode("another region")
+ .setType(NumberType.TOLL_FREE)
+ .setNumberPattern(
+ NumberPattern.builder()
+ .setPattern("pattern value")
+ .setSearchPattern(SearchPattern.END)
+ .build())
+ .setCapabilities(Collections.singletonList(Capability.VOICE))
+ .setPageSize(5)
+ .setPageToken("foo")
+ .setOrderBy(OrderBy.PHONE_NUMBER)
+ .build();
+
+ Page expected =
+ new Page<>(
+ ActiveNumberListRequestParameters.builder()
+ .setRegionCode("another region")
+ .setType(NumberType.TOLL_FREE)
+ .setNumberPattern(
+ NumberPattern.builder()
+ .setPattern("pattern value")
+ .setSearchPattern(SearchPattern.END)
+ .build())
+ .setCapabilities(Collections.singletonList(Capability.VOICE))
+ .setPageSize(5)
+ .setPageToken("foo")
+ .setOrderBy(OrderBy.PHONE_NUMBER)
+ .build(),
+ Collections.singletonList(
+ ActiveNumber.builder()
+ .setPhoneNumber("+447520651116XYZ")
+ .setProjectId("project id")
+ .setRegionCode("GB")
+ .setType(NumberType.MOBILE)
+ .setCapability(Arrays.asList(Capability.SMS, Capability.VOICE))
+ .setDisplayName("a display")
+ .setMoney(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setNextChargeDate(Instant.parse("2023-09-22T15:49:58.813424Z"))
+ .setExpireAt(Instant.parse("2023-10-06T15:49:58.813381Z"))
+ .setSmsConfiguration(
+ new SMSConfiguration(
+ "service plan id",
+ null,
+ new ScheduledSmsProvisioning(
+ "service plan id from scheduled",
+ "campaign id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ Collections.singletonList(SmsErrorCode.ERROR_CODE_UNSPECIFIED))))
+ .setVoiceConfiguration(
+ new VoiceConfiguration(
+ "app id",
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ new ScheduledVoiceProvisioning(
+ "app id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"))))
+ .setCallbackUrl("foo callback")
+ .build()),
+ new PageToken<>("foo"));
+
+ ActiveNumberListResponse response = service.list(parameters);
+
+ Assertions.assertThat(response.getContent())
+ .usingRecursiveComparison()
+ .isEqualTo(expected.getEntities());
+ }
+
+ @Test
+ void get() throws ApiException {
+
+ when(api.numberServiceGetActiveNumber(eq(configuration.getProjectId()), eq("foo phone number")))
+ .thenReturn(activeGetResponseDto);
+
+ ActiveNumber expected =
+ ActiveNumber.builder()
+ .setPhoneNumber("+447520651116XYZ")
+ .setProjectId("project id")
+ .setRegionCode("GB")
+ .setType(NumberType.MOBILE)
+ .setCapability(Arrays.asList(Capability.SMS, Capability.VOICE))
+ .setDisplayName("a display")
+ .setMoney(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setNextChargeDate(Instant.parse("2023-09-22T15:49:58.813424Z"))
+ .setExpireAt(Instant.parse("2023-10-06T15:49:58.813381Z"))
+ .setSmsConfiguration(
+ new SMSConfiguration(
+ "service plan id",
+ null,
+ new ScheduledSmsProvisioning(
+ "service plan id from scheduled",
+ "campaign id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ Collections.singletonList(SmsErrorCode.ERROR_CODE_UNSPECIFIED))))
+ .setVoiceConfiguration(
+ new VoiceConfiguration(
+ "app id",
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ new ScheduledVoiceProvisioning(
+ "app id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"))))
+ .setCallbackUrl("foo callback")
+ .build();
+
+ ActiveNumber response = service.get("foo phone number");
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ void release() throws ApiException {
+
+ when(api.numberServiceReleaseNumber(eq(configuration.getProjectId()), eq("foo phone number")))
+ .thenReturn(activeGetResponseDto);
+
+ ActiveNumber expected =
+ ActiveNumber.builder()
+ .setPhoneNumber("+447520651116XYZ")
+ .setProjectId("project id")
+ .setRegionCode("GB")
+ .setType(NumberType.MOBILE)
+ .setCapability(Arrays.asList(Capability.SMS, Capability.VOICE))
+ .setDisplayName("a display")
+ .setMoney(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setNextChargeDate(Instant.parse("2023-09-22T15:49:58.813424Z"))
+ .setExpireAt(Instant.parse("2023-10-06T15:49:58.813381Z"))
+ .setSmsConfiguration(
+ new SMSConfiguration(
+ "service plan id",
+ null,
+ new ScheduledSmsProvisioning(
+ "service plan id from scheduled",
+ "campaign id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ Collections.singletonList(SmsErrorCode.ERROR_CODE_UNSPECIFIED))))
+ .setVoiceConfiguration(
+ new VoiceConfiguration(
+ "app id",
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ new ScheduledVoiceProvisioning(
+ "app id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"))))
+ .setCallbackUrl("foo callback")
+ .build();
+
+ ActiveNumber response = service.release("foo phone number");
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ void update() {
+
+ ActiveNumberUpdateSMSConfigurationRequestParameters smsConfiguration =
+ ActiveNumberUpdateSMSConfigurationRequestParameters.builder()
+ .setServicePlanId("service plan id")
+ .setCampaignId("campaign id")
+ .build();
+
+ ActiveNumberUpdateVoiceConfigurationRequestParameters voiceConfiguration =
+ ActiveNumberUpdateVoiceConfigurationRequestParameters.builder().setAppId("app id").build();
+ ActiveNumberUpdateRequestParameters parameters =
+ ActiveNumberUpdateRequestParameters.builder()
+ .setDisplayName("my display name")
+ .setSmsConfiguration(smsConfiguration)
+ .setVoiceConfiguration(voiceConfiguration)
+ .setCallback("foo callback")
+ .build();
+
+ when(api.numberServiceUpdateActiveNumber(
+ eq(configuration.getProjectId()),
+ eq("foo phone number"),
+ ArgumentMatchers.eq(
+ ActiveNumberUpdateRequestParametersDtoConverter.convert(parameters))))
+ .thenReturn(activeGetResponseDto);
+
+ ActiveNumber expected =
+ ActiveNumber.builder()
+ .setPhoneNumber("+447520651116XYZ")
+ .setProjectId("project id")
+ .setRegionCode("GB")
+ .setType(NumberType.MOBILE)
+ .setCapability(Arrays.asList(Capability.SMS, Capability.VOICE))
+ .setDisplayName("a display")
+ .setMoney(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setNextChargeDate(Instant.parse("2023-09-22T15:49:58.813424Z"))
+ .setExpireAt(Instant.parse("2023-10-06T15:49:58.813381Z"))
+ .setSmsConfiguration(
+ new SMSConfiguration(
+ "service plan id",
+ null,
+ new ScheduledSmsProvisioning(
+ "service plan id from scheduled",
+ "campaign id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ Collections.singletonList(SmsErrorCode.ERROR_CODE_UNSPECIFIED))))
+ .setVoiceConfiguration(
+ new VoiceConfiguration(
+ "app id",
+ Instant.parse("2023-09-25T12:08:02.115Z"),
+ new ScheduledVoiceProvisioning(
+ "app id from scheduled",
+ ProvisioningStatus.PROVISIONING_STATUS_UNSPECIFIED,
+ Instant.parse("2023-09-25T12:08:02.115Z"))))
+ .setCallbackUrl("foo callback")
+ .build();
+
+ ActiveNumber response = service.update("foo phone number", parameters);
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/AvailableNumberServiceTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/AvailableNumberServiceTest.java
new file mode 100644
index 00000000..b4396163
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/AvailableNumberServiceTest.java
@@ -0,0 +1,272 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.AvailableNumberApi;
+import com.sinch.sdk.domains.numbers.models.*;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumbersResponseDto;
+import com.sinch.sdk.domains.numbers.models.requests.*;
+import com.sinch.sdk.domains.numbers.models.responses.AvailableNumberListResponse;
+import com.sinch.sdk.models.Configuration;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.NoSuchElementException;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatchers;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+@TestWithResources
+class AvailableNumberServiceTest extends BaseTest {
+
+ @GivenJsonResource("/domains/numbers/v1/available-numbers-list.json")
+ AvailableNumbersResponseDto availableNumbersListDto;
+
+ @GivenJsonResource("/domains/numbers/v1/available-numbers-get.json")
+ AvailableNumberDto getNumberDto;
+
+ @GivenJsonResource("/domains/numbers/v1/rent-response.json")
+ ActiveNumberDto rentNumberDto;
+
+ @Mock Configuration configuration;
+ @Mock AvailableNumberApi api;
+ @InjectMocks AvailableNumberService service;
+
+ @Test
+ void list() throws ApiException {
+
+ when(api.numberServiceListAvailableNumbers(
+ eq(configuration.getProjectId()),
+ eq("region"),
+ ArgumentMatchers.eq(NumberType.MOBILE.value()),
+ eq(null),
+ eq(null),
+ eq(null),
+ eq(null)))
+ .thenReturn(availableNumbersListDto);
+
+ AvailableNumberListAllRequestParameters parameters =
+ AvailableNumberListAllRequestParameters.builder()
+ .setRegionCode("region")
+ .setType(NumberType.MOBILE)
+ .build();
+
+ Collection expected =
+ Collections.singletonList(
+ AvailableNumber.builder()
+ .setPhoneNumber("+46650553763")
+ .setRegionCode("SE")
+ .setType(NumberType.LOCAL)
+ .setCapability(Collections.singletonList(Capability.VOICE))
+ .setSetupPrice(new Money("DOLLAR", 0.57))
+ .setMonthlyPrice(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setSupportingDocumentationRequired(true)
+ .build());
+
+ AvailableNumberListResponse response = service.list(parameters);
+
+ assertFalse(response.hasNextPage(), "Has no next page");
+ assertThrows(NoSuchElementException.class, response::nextPage);
+ Assertions.assertThat(response.getContent()).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ void listWithParameters() throws ApiException {
+
+ when(api.numberServiceListAvailableNumbers(
+ eq(configuration.getProjectId()),
+ eq("another region"),
+ ArgumentMatchers.eq(NumberType.TOLL_FREE.value()),
+ eq("pattern value"),
+ ArgumentMatchers.eq(SearchPattern.END.value()),
+ ArgumentMatchers.eq(Collections.singletonList(Capability.VOICE.value())),
+ eq(45)))
+ .thenReturn(availableNumbersListDto);
+
+ AvailableNumberListAllRequestParameters parameters =
+ AvailableNumberListAllRequestParameters.builder()
+ .setRegionCode("another region")
+ .setType(NumberType.TOLL_FREE)
+ .setNumberPattern(
+ NumberPattern.builder()
+ .setPattern("pattern value")
+ .setSearchPattern(SearchPattern.END)
+ .build())
+ .setCapabilities(Collections.singletonList(Capability.VOICE))
+ .setSize(45)
+ .build();
+
+ Collection expected =
+ Collections.singletonList(
+ AvailableNumber.builder()
+ .setPhoneNumber("+46650553763")
+ .setRegionCode("SE")
+ .setType(NumberType.LOCAL)
+ .setCapability(Collections.singletonList(Capability.VOICE))
+ .setSetupPrice(new Money("DOLLAR", 0.57))
+ .setMonthlyPrice(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setSupportingDocumentationRequired(true)
+ .build());
+
+ AvailableNumberListResponse response = service.list(parameters);
+
+ assertFalse(response.hasNextPage(), "Has no next page");
+ assertThrows(NoSuchElementException.class, response::nextPage);
+ Assertions.assertThat(response.getContent()).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ void get() {
+
+ when(api.numberServiceGetAvailableNumber(eq(configuration.getProjectId()), eq("foo")))
+ .thenReturn(getNumberDto);
+
+ AvailableNumber response = service.get("foo");
+
+ AvailableNumber expected =
+ AvailableNumber.builder()
+ .setPhoneNumber("+46650553763")
+ .setRegionCode("SE")
+ .setType(NumberType.LOCAL)
+ .setCapability(Collections.singletonList(Capability.VOICE))
+ .setSetupPrice(new Money("DOLLAR", 0.57))
+ .setMonthlyPrice(new Money("EUR", 0.80))
+ .setPaymentIntervalMonths(1)
+ .setSupportingDocumentationRequired(true)
+ .build();
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ void rent() {
+
+ when(api.numberServiceRentNumber(eq(configuration.getProjectId()), eq("foo"), any()))
+ .thenReturn(rentNumberDto);
+
+ ActiveNumber response =
+ service.rent(
+ "foo",
+ new AvailableNumberRentRequestParameters(
+ new RentSMSConfigurationRequestParameters("", ""),
+ new RentVoiceConfigurationRequestParameters(""),
+ "foo"));
+ ActiveNumber expected =
+ ActiveNumber.builder()
+ .setRegionCode("US")
+ .setPaymentIntervalMonths(0)
+ .setNextChargeDate(
+ OffsetDateTime.parse("2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant())
+ .setExpireAt(
+ OffsetDateTime.parse("2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant())
+ .setPhoneNumber("+12025550134")
+ .setProjectId("51bc3f40-f266-4ca8-8938-a1ed0ff32b9a")
+ .setDisplayName("string")
+ .setType(NumberType.MOBILE)
+ .setCapability(Collections.singletonList(Capability.SMS))
+ .setMoney(new Money("USD", 2.00))
+ .setSmsConfiguration(
+ new SMSConfiguration(
+ "string",
+ "string",
+ new ScheduledSmsProvisioning(
+ "8200000f74924bd6800000b212f00000",
+ "string",
+ ProvisioningStatus.WAITING,
+ OffsetDateTime.parse(
+ "2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant(),
+ Collections.emptyList())))
+ .setVoiceConfiguration(
+ new VoiceConfiguration(
+ "string",
+ OffsetDateTime.parse(
+ "2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant(),
+ new ScheduledVoiceProvisioning(
+ "string",
+ ProvisioningStatus.WAITING,
+ OffsetDateTime.parse(
+ "2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant())))
+ .setCallbackUrl("https://www.your-callback-server.com/callback")
+ .build();
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ void rentAny() {
+
+ when(api.numberServiceRentAnyNumber(eq(configuration.getProjectId()), any()))
+ .thenReturn(rentNumberDto);
+
+ AvailableNumberRentAnyRequestParameters parameters =
+ AvailableNumberRentAnyRequestParameters.builder()
+ .setRegionCode("foo region")
+ .setType(NumberType.MOBILE)
+ .build();
+ ActiveNumber response = service.rentAny(parameters);
+ ActiveNumber expected =
+ ActiveNumber.builder()
+ .setRegionCode("US")
+ .setPaymentIntervalMonths(0)
+ .setNextChargeDate(
+ OffsetDateTime.parse("2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant())
+ .setExpireAt(
+ OffsetDateTime.parse("2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant())
+ .setPhoneNumber("+12025550134")
+ .setProjectId("51bc3f40-f266-4ca8-8938-a1ed0ff32b9a")
+ .setDisplayName("string")
+ .setType(NumberType.MOBILE)
+ .setCapability(Collections.singletonList(Capability.SMS))
+ .setMoney(new Money("USD", 2.00))
+ .setSmsConfiguration(
+ new SMSConfiguration(
+ "string",
+ "string",
+ new ScheduledSmsProvisioning(
+ "8200000f74924bd6800000b212f00000",
+ "string",
+ ProvisioningStatus.WAITING,
+ OffsetDateTime.parse(
+ "2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant(),
+ Collections.emptyList())))
+ .setVoiceConfiguration(
+ new VoiceConfiguration(
+ "string",
+ OffsetDateTime.parse(
+ "2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant(),
+ new ScheduledVoiceProvisioning(
+ "string",
+ ProvisioningStatus.WAITING,
+ OffsetDateTime.parse(
+ "2019-08-24T14:15:22Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME)
+ .toInstant())))
+ .setCallbackUrl("https://www.your-callback-server.com/callback")
+ .build();
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/CallbackConfigurationServiceTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/CallbackConfigurationServiceTest.java
new file mode 100644
index 00000000..6e76aa7f
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/CallbackConfigurationServiceTest.java
@@ -0,0 +1,69 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.CallbackConfigurationApi;
+import com.sinch.sdk.domains.numbers.models.CallbackConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.CallbackConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.CallbackConfigurationUpdateDto;
+import com.sinch.sdk.domains.numbers.models.requests.CallbackConfigurationUpdateRequestParameters;
+import com.sinch.sdk.models.Configuration;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+@TestWithResources
+class CallbackConfigurationServiceTest extends BaseTest {
+
+ @GivenJsonResource("/domains/numbers/v1/callback-configuration.json")
+ CallbackConfigurationDto callbackConfigurationDto;
+
+ @Mock Configuration configuration;
+ @Mock CallbackConfigurationApi api;
+ @InjectMocks CallbackConfigurationService service;
+
+ @Test
+ void get() throws ApiException {
+
+ when(api.getCallbackConfiguration(eq(configuration.getProjectId())))
+ .thenReturn(callbackConfigurationDto);
+
+ CallbackConfiguration response = service.get();
+
+ CallbackConfiguration expected =
+ CallbackConfiguration.builder()
+ .setProjectId("The project ID")
+ .setHMACSecret("The secret HMAC")
+ .build();
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+
+ @Test
+ void update() throws ApiException {
+
+ CallbackConfigurationUpdateDto dtoParameters =
+ new CallbackConfigurationUpdateDto().hmacSecret("hmac value");
+ CallbackConfigurationUpdateRequestParameters parameters =
+ CallbackConfigurationUpdateRequestParameters.builder().setHMACSecret("hmac value").build();
+
+ when(api.updateCallbackConfiguration(eq(configuration.getProjectId()), eq(dtoParameters)))
+ .thenReturn(callbackConfigurationDto);
+
+ CallbackConfiguration response = service.update(parameters);
+
+ CallbackConfiguration expected =
+ CallbackConfiguration.builder()
+ .setProjectId("The project ID")
+ .setHMACSecret("The secret HMAC")
+ .build();
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(expected);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/RegionServiceTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/RegionServiceTest.java
new file mode 100644
index 00000000..dcc92687
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/RegionServiceTest.java
@@ -0,0 +1,57 @@
+package com.sinch.sdk.domains.numbers.adapters;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.domains.numbers.adapters.api.v1.AvailableRegionsApi;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.Region;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ListAvailableRegionsResponseDto;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableRegionListAllRequestParameters;
+import com.sinch.sdk.domains.numbers.models.responses.AvailableRegionListResponse;
+import com.sinch.sdk.models.Configuration;
+import java.util.Collection;
+import java.util.Collections;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+@TestWithResources
+class RegionServiceTest extends BaseTest {
+
+ @GivenJsonResource("/domains/numbers/v1/available-regions-list.json")
+ ListAvailableRegionsResponseDto availableRegionsListDto;
+
+ @Mock Configuration configuration;
+ @Mock AvailableRegionsApi api;
+ @InjectMocks AvailableRegionService service;
+
+ @Test
+ void list() throws ApiException {
+
+ when(api.numberServiceListAvailableRegions(
+ eq(configuration.getProjectId()), eq(Collections.singletonList("MOBILE"))))
+ .thenReturn(availableRegionsListDto);
+
+ AvailableRegionListResponse response =
+ service.list(
+ AvailableRegionListAllRequestParameters.builder()
+ .setTypes(Collections.singletonList(NumberType.MOBILE))
+ .build());
+
+ Collection expected =
+ Collections.singletonList(
+ Region.builder()
+ .setRegionName("Australia")
+ .setRegionCode("AU")
+ .setTypes(Collections.singletonList(NumberType.MOBILE))
+ .build());
+
+ Assertions.assertThat(response.getContent()).usingRecursiveComparison().isEqualTo(expected);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberDtoConverterTest.java
new file mode 100644
index 00000000..332b6360
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberDtoConverterTest.java
@@ -0,0 +1,72 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.core.models.pagination.PageToken;
+import com.sinch.sdk.core.utils.Pair;
+import com.sinch.sdk.domains.numbers.models.ActiveNumber;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumbersResponseDto;
+import java.time.OffsetDateTime;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class ActiveNumberDtoConverterTest {
+
+ static final OffsetDateTime offset1 = OffsetDateTime.now();
+ ActiveNumberDto dtoItem;
+
+ public static void compareWithDto(ActiveNumber client, ActiveNumberDto dto) {
+ assertEquals(dto.getPhoneNumber(), client.getPhoneNumber());
+ assertEquals(dto.getProjectId(), client.getProjectId());
+ assertEquals(dto.getDisplayName(), client.getDisplayName());
+ assertEquals(dto.getRegionCode(), client.getRegionCode());
+ assertEquals(dto.getType(), NumberType.valueOf(client.getType()));
+ assertEquals(
+ null == dto.getCapability() ? null : dto.getCapability(),
+ null == client.getCapability()
+ ? null
+ : client.getCapability().stream()
+ .map(Capability::valueOf)
+ .collect(Collectors.toList()));
+ MoneyDtoConverterTest.compareWithDto(client.getMoney(), dto.getMoney());
+ assertEquals(dto.getPaymentIntervalMonths(), client.getPaymentIntervalMonths());
+ assertEquals(dto.getNextChargeDate().toInstant(), client.getNextChargeDate());
+ assertEquals(dto.getExpireAt().toInstant(), client.getExpireAt());
+ SmsConfigurationDtoConverterTest.compareWithDto(
+ client.getSmsConfiguration(), dto.getSmsConfiguration());
+ VoiceConfigurationDtoConverterTest.compareWithDto(
+ client.getVoiceConfiguration(), dto.getVoiceConfiguration());
+ assertEquals(dto.getCallbackUrl(), client.getCallbackUrl());
+ }
+
+ @Test
+ void convertActiveNumbersResponseDto() {
+ ActiveNumbersResponseDto dto = new ActiveNumbersResponseDto();
+ dto.setActiveNumbers(Collections.singletonList(dtoItem));
+
+ Pair, PageToken> converted =
+ ActiveNumberDtoConverter.convert(dto);
+
+ assertEquals(dto.getActiveNumbers().size(), converted.getLeft().size());
+ assertEquals(dto.getNextPageToken(), converted.getRight().getToken());
+ compareWithDto(converted.getLeft().stream().findFirst().get(), dto.getActiveNumbers().get(0));
+ }
+
+ @Test
+ void convertActiveNumberDto() {
+ ActiveNumberDto dto = dtoItem;
+ ActiveNumber converted = ActiveNumberDtoConverter.convert(dtoItem);
+ compareWithDto(converted, dto);
+ }
+
+ @BeforeEach
+ void setUp() {
+ dtoItem = new ActiveNumberDto("phoneNumber", 4, offset1, OffsetDateTime.MAX);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberUpdateRequestParametersDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberUpdateRequestParametersDtoConverterTest.java
new file mode 100644
index 00000000..298be9d4
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ActiveNumberUpdateRequestParametersDtoConverterTest.java
@@ -0,0 +1,65 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.dto.v1.ActiveNumberRequestDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.SMSConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.VoiceConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateSMSConfigurationRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberUpdateVoiceConfigurationRequestParameters;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class ActiveNumberUpdateRequestParametersDtoConverterTest {
+
+ ActiveNumberUpdateRequestParameters item;
+
+ public static void compareWithDto(
+ ActiveNumberUpdateSMSConfigurationRequestParameters client, SMSConfigurationDto dto) {
+ assertEquals(dto.getServicePlanId(), client.getServicePlanId());
+ assertEquals(dto.getCampaignId(), client.getCampaignId().get());
+ }
+
+ public static void compareWithDto(
+ ActiveNumberUpdateVoiceConfigurationRequestParameters client, VoiceConfigurationDto dto) {
+ assertEquals(dto.getAppId(), client.getAppId());
+ }
+
+ public static void compareWithDto(
+ ActiveNumberUpdateRequestParameters client, ActiveNumberRequestDto dto) {
+ assertEquals(dto.getDisplayName(), client.getDisplayName().get());
+ compareWithDto(client.getSmsConfiguration().get(), dto.getSmsConfiguration());
+ compareWithDto(client.getVoiceConfiguration().get(), dto.getVoiceConfiguration());
+ // TODO: OAS file do not yet contains callback field declaration
+ // assertEquals(dto.getCallback(),
+ // client.getCallback());
+
+ }
+
+ @Test
+ void convert() {
+ ActiveNumberRequestDto converted =
+ ActiveNumberUpdateRequestParametersDtoConverter.convert(item);
+ compareWithDto(item, converted);
+ }
+
+ @BeforeEach
+ void setUp() {
+ ActiveNumberUpdateSMSConfigurationRequestParameters smsConfiguration =
+ ActiveNumberUpdateSMSConfigurationRequestParameters.builder()
+ .setServicePlanId("service plan id")
+ .setCampaignId("campaign id")
+ .build();
+
+ ActiveNumberUpdateVoiceConfigurationRequestParameters voiceConfiguration =
+ ActiveNumberUpdateVoiceConfigurationRequestParameters.builder().setAppId("app id").build();
+ item =
+ ActiveNumberUpdateRequestParameters.builder()
+ .setDisplayName("my display name")
+ .setSmsConfiguration(smsConfiguration)
+ .setVoiceConfiguration(voiceConfiguration)
+ .setCallback("foo callback")
+ .build();
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableNumberDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableNumberDtoConverterTest.java
new file mode 100644
index 00000000..c900d911
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableNumberDtoConverterTest.java
@@ -0,0 +1,81 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.AvailableNumber;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumberDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableNumbersResponseDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.MoneyDto;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberDtoConverterTest {
+
+ AvailableNumberDto dtoItem;
+
+ public static void compareWithDto(AvailableNumber client, AvailableNumberDto dto) {
+ assertEquals(dto.getPhoneNumber(), client.getPhoneNumber());
+ assertEquals(dto.getRegionCode(), client.getRegionCode());
+ assertEquals(dto.getType(), NumberType.valueOf(client.getType()));
+ assertEquals(
+ null == dto.getCapability() ? null : dto.getCapability(),
+ null == client.getCapability()
+ ? null
+ : client.getCapability().stream()
+ .map(Capability::valueOf)
+ .collect(Collectors.toList()));
+ MoneyDtoConverterTest.compareWithDto(client.getSetupPrice(), dto.getSetupPrice());
+ MoneyDtoConverterTest.compareWithDto(client.getMonthlyPrice(), dto.getMonthlyPrice());
+ assertEquals(dto.getPaymentIntervalMonths(), client.getPaymentIntervalMonths());
+ assertEquals(
+ dto.getSupportingDocumentationRequired(), client.getSupportingDocumentationRequired());
+ }
+
+ @Test
+ void convertAvailableNumbersResponseDto() {
+ AvailableNumbersResponseDto dto = new AvailableNumbersResponseDto();
+ dto.setAvailableNumbers(Collections.singletonList(dtoItem));
+
+ Collection converted = AvailableNumberDtoConverter.convert(dto);
+
+ assertEquals(dto.getAvailableNumbers().size(), converted.size());
+ }
+
+ @Test
+ void convertEmptyAvailableNumbersResponseDto() {
+ AvailableNumbersResponseDto dto = new AvailableNumbersResponseDto();
+ Collection converted = AvailableNumberDtoConverter.convert(dto);
+
+ assertEquals(converted.size(), 0);
+ }
+
+ @Test
+ void convertAvailableNumberDto() {
+ AvailableNumberDto dto = dtoItem;
+ AvailableNumber converted = AvailableNumberDtoConverter.convert(dtoItem);
+ compareWithDto(converted, dto);
+ }
+
+ @Test
+ void convertAvailableNumberDtoWithUnknownType() {
+ dtoItem =
+ new AvailableNumberDto("phoneNumber", "regionCode", 4, true)
+ .type("foo")
+ .addCapabilityItem(Capability.SMS.value())
+ .addCapabilityItem(Capability.VOICE.value())
+ .setupPrice(new MoneyDto().currencyCode("EU").amount(".8"))
+ .monthlyPrice(new MoneyDto().currencyCode("EU").amount(".15"));
+ AvailableNumber converted = AvailableNumberDtoConverter.convert(dtoItem);
+ compareWithDto(converted, dtoItem);
+ }
+
+ @BeforeEach
+ void setUp() {
+ dtoItem = new AvailableNumberDto("phoneNumber", "regionCode", 4, true);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentAnyRequestParametersDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentAnyRequestParametersDtoConverterTest.java
new file mode 100644
index 00000000..74c0812c
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentAnyRequestParametersDtoConverterTest.java
@@ -0,0 +1,92 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.SearchPattern;
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentAnyNumberRequestDto;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentAnyRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.RentSMSConfigurationRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.RentVoiceConfigurationRequestParameters;
+import java.util.Collections;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class AvailableRentAnyRequestParametersDtoConverterTest {
+
+ AvailableNumberRentAnyRequestParameters item;
+
+ public static void compareWithDto(
+ AvailableNumberRentAnyRequestParameters client, RentAnyNumberRequestDto dto) {
+ assertEquals(dto.getRegionCode(), client.getRegionCode());
+ assertEquals(dto.getType(), NumberType.valueOf(client.getType()));
+ if (null == dto.getNumberPattern()) {
+ assertFalse(client.getNumberPattern().isPresent());
+ } else {
+ assertEquals(
+ dto.getNumberPattern().getPattern(), client.getNumberPattern().get().getPattern());
+ assertEquals(
+ dto.getNumberPattern().getSearchPattern(),
+ client.getNumberPattern().get().getSearchPattern().value());
+ }
+ if (null == dto.getCapabilities()) {
+ assertFalse(client.getCapabilities().isPresent());
+ } else {
+ assertEquals(
+ dto.getCapabilities(),
+ client.getCapabilities().get().stream()
+ .map(Capability::valueOf)
+ .collect(Collectors.toList()));
+ }
+ if (null == dto.getSmsConfiguration()) {
+ assertFalse(client.getSmsConfiguration().isPresent());
+ } else {
+ assertEquals(
+ dto.getSmsConfiguration().getCampaignId(),
+ client.getSmsConfiguration().get().getCampaignId().get());
+ assertEquals(
+ dto.getSmsConfiguration().getServicePlanId(),
+ client.getSmsConfiguration().get().getServicePlanId());
+ }
+ if (null == dto.getVoiceConfiguration()) {
+ assertFalse(client.getVoiceConfiguration().isPresent());
+ } else {
+ assertEquals(
+ dto.getVoiceConfiguration().getAppId(), client.getVoiceConfiguration().get().getAppId());
+ }
+ if (null == dto.getCallbackUrl()) {
+ assertFalse(client.getCallBackUrl().isPresent());
+ } else {
+ assertEquals(dto.getCallbackUrl(), client.getCallBackUrl().get());
+ }
+ }
+
+ @Test
+ void convert() {
+ RentAnyNumberRequestDto converted = AvailableRentAnyRequestParametersDtoConverter.convert(item);
+ compareWithDto(item, converted);
+ }
+
+ @BeforeEach
+ void setUp() {
+ item =
+ AvailableNumberRentAnyRequestParameters.builder()
+ .setRegionCode("region code")
+ .setType(NumberType.from("foo type"))
+ .setNumberPattern(
+ NumberPattern.builder()
+ .setPattern("pattern")
+ .setSearchPattern(SearchPattern.CONTAINS)
+ .build())
+ .setCapabilities(Collections.singletonList(Capability.SMS))
+ .setSmsConfiguration(
+ new RentSMSConfigurationRequestParameters("campaign id", ("service plan")))
+ .setVoiceConfiguration(new RentVoiceConfigurationRequestParameters("app id"))
+ .setCallbackUrl("callback url")
+ .build();
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentRequestParametersDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentRequestParametersDtoConverterTest.java
new file mode 100644
index 00000000..ac75efc6
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/AvailableRentRequestParametersDtoConverterTest.java
@@ -0,0 +1,58 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+import com.sinch.sdk.domains.numbers.models.dto.v1.RentNumberRequestDto;
+import com.sinch.sdk.domains.numbers.models.requests.AvailableNumberRentRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.RentSMSConfigurationRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.RentVoiceConfigurationRequestParameters;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class AvailableRentRequestParametersDtoConverterTest {
+ AvailableNumberRentRequestParameters item;
+
+ public static void compareWithDto(
+ AvailableNumberRentRequestParameters client, RentNumberRequestDto dto) {
+
+ if (null == dto.getSmsConfiguration()) {
+ assertFalse(client.getSmsConfiguration().isPresent());
+ } else {
+ assertEquals(
+ dto.getSmsConfiguration().getCampaignId(),
+ client.getSmsConfiguration().get().getCampaignId().get());
+ assertEquals(
+ dto.getSmsConfiguration().getServicePlanId(),
+ client.getSmsConfiguration().get().getServicePlanId());
+ }
+ if (null == dto.getVoiceConfiguration()) {
+ assertFalse(client.getVoiceConfiguration().isPresent());
+ } else {
+ assertEquals(
+ dto.getVoiceConfiguration().getAppId(), client.getVoiceConfiguration().get().getAppId());
+ }
+ if (null == dto.getCallbackUrl()) {
+ assertFalse(client.getCallBackUrl().isPresent());
+ } else {
+ assertEquals(dto.getCallbackUrl(), client.getCallBackUrl().get());
+ }
+ }
+
+ @Test
+ void convert() {
+ RentNumberRequestDto converted = AvailableRentRequestParametersDtoConverter.convert(item);
+ compareWithDto(item, converted);
+ }
+
+ @BeforeEach
+ void setUp() {
+ item =
+ AvailableNumberRentRequestParameters.builder()
+ .setSmsConfiguration(
+ new RentSMSConfigurationRequestParameters("campaign id", ("service plan")))
+ .setVoiceConfiguration(new RentVoiceConfigurationRequestParameters("app id"))
+ .setCallbackUrl("callback url")
+ .build();
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationDtoConverterTest.java
new file mode 100644
index 00000000..a7b9c8eb
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationDtoConverterTest.java
@@ -0,0 +1,28 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.CallbackConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.CallbackConfigurationDto;
+import org.junit.jupiter.api.Test;
+
+class CallbackConfigurationDtoConverterTest {
+
+ public static void compareWithDto(CallbackConfiguration client, CallbackConfigurationDto dto) {
+ if (null == client && null == dto) {
+ return;
+ }
+ assertEquals(dto.getProjectId(), client.getProjectId());
+ assertEquals(dto.getHmacSecret(), client.getHMACSecret());
+ }
+
+ @Test
+ void convert() {
+ CallbackConfigurationDto dto = new CallbackConfigurationDto();
+ dto.setProjectId("my project");
+ dto.setHmacSecret("a HMAC secret");
+
+ CallbackConfiguration converted = CallbackConfigurationDtoConverter.convert(dto);
+ compareWithDto(converted, dto);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationUpdateParametersDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationUpdateParametersDtoConverterTest.java
new file mode 100644
index 00000000..838f3c0e
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/CallbackConfigurationUpdateParametersDtoConverterTest.java
@@ -0,0 +1,31 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.dto.v1.CallbackConfigurationUpdateDto;
+import com.sinch.sdk.domains.numbers.models.requests.CallbackConfigurationUpdateRequestParameters;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class CallbackConfigurationUpdateParametersDtoConverterTest {
+
+ CallbackConfigurationUpdateRequestParameters item;
+
+ public static void compareWithDto(
+ CallbackConfigurationUpdateRequestParameters client, CallbackConfigurationUpdateDto dto) {
+ assertEquals(dto.getHmacSecret(), client.getHMACSecret());
+ }
+
+ @Test
+ void convert() {
+ CallbackConfigurationUpdateDto converted =
+ CallbackConfigurationUpdateRequestParametersDtoConverter.convert(item);
+ compareWithDto(item, converted);
+ }
+
+ @BeforeEach
+ void setUp() {
+
+ item = CallbackConfigurationUpdateRequestParameters.builder().setHMACSecret("my HMAC").build();
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/MoneyDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/MoneyDtoConverterTest.java
new file mode 100644
index 00000000..a680354c
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/MoneyDtoConverterTest.java
@@ -0,0 +1,28 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.Money;
+import com.sinch.sdk.domains.numbers.models.dto.v1.MoneyDto;
+import org.junit.jupiter.api.Test;
+
+class MoneyDtoConverterTest {
+
+ public static void compareWithDto(Money client, MoneyDto dto) {
+ if (null == client && null == dto) {
+ return;
+ }
+ assertEquals(Double.valueOf(dto.getAmount()), client.getAmount());
+ assertEquals(dto.getCurrencyCode(), client.getCurrencyCode());
+ }
+
+ @Test
+ void convert() {
+ MoneyDto dto = new MoneyDto();
+ dto.setAmount("15.37");
+ dto.setCurrencyCode("currency code");
+
+ Money converted = MoneyDtoConverter.convert(dto);
+ compareWithDto(converted, dto);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/RegionsDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/RegionsDtoConverterTest.java
new file mode 100644
index 00000000..7785bd30
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/RegionsDtoConverterTest.java
@@ -0,0 +1,59 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.Region;
+import com.sinch.sdk.domains.numbers.models.dto.v1.AvailableRegionDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ListAvailableRegionsResponseDto;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class RegionsDtoConverterTest {
+
+ AvailableRegionDto dtoItem;
+
+ public static void compareWithDto(Region client, AvailableRegionDto dto) {
+ assertEquals(dto.getRegionCode(), client.getRegionCode());
+ assertEquals(dto.getRegionName(), client.getRegionName());
+ assertEquals(
+ null == dto.getTypes() ? null : dto.getTypes(),
+ null == client.getTypes()
+ ? null
+ : client.getTypes().stream().map(NumberType::valueOf).collect(Collectors.toList()));
+ }
+
+ @Test
+ void convertListAvailableRegionsResponseDto() {
+ ListAvailableRegionsResponseDto dto = new ListAvailableRegionsResponseDto();
+ dto.setAvailableRegions(Collections.singletonList(dtoItem));
+
+ Collection converted = AvailableRegionsDtoConverter.convert(dto);
+
+ assertEquals(dto.getAvailableRegions().size(), converted.size());
+ }
+
+ @Test
+ void convertEmptyListAvailableRegionsResponseDto() {
+ ListAvailableRegionsResponseDto dto = new ListAvailableRegionsResponseDto();
+ Collection converted = AvailableRegionsDtoConverter.convert(dto);
+
+ assertEquals(converted.size(), 0);
+ }
+
+ @Test
+ void convertAvailableNumberDto() {
+ AvailableRegionDto dto = dtoItem;
+ Region converted = AvailableRegionsDtoConverter.convert(dtoItem);
+ compareWithDto(converted, dto);
+ }
+
+ @BeforeEach
+ void setUp() {
+ dtoItem = new AvailableRegionDto("region code", "region name", Arrays.asList("MOBILE", "foo"));
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledSmsProvisioningDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledSmsProvisioningDtoConverterTest.java
new file mode 100644
index 00000000..04e9666d
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledSmsProvisioningDtoConverterTest.java
@@ -0,0 +1,47 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.ScheduledSmsProvisioning;
+import com.sinch.sdk.domains.numbers.models.SmsErrorCode;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ProvisioningStatusDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ScheduledProvisioningDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.SmsErrorCodeDto;
+import java.time.OffsetDateTime;
+import java.util.Collections;
+import java.util.stream.Collectors;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ScheduledSmsProvisioningDtoConverterTest {
+
+ public static void compareWithDto(ScheduledSmsProvisioning client, ScheduledProvisioningDto dto) {
+ if (null == client && null == dto) {
+ return;
+ }
+ assertEquals(dto.getServicePlanId(), client.getServicePlanId());
+ assertEquals(dto.getCampaignId(), client.getCampaignId());
+ assertEquals(dto.getLastUpdatedTime().toInstant(), client.getLastUpdatedTime());
+ assertEquals(dto.getStatus().getValue(), client.getStatus().value());
+ Assertions.assertThat(dto.getErrorCodes().stream().map(Enum::name).collect(Collectors.toList()))
+ .usingRecursiveComparison()
+ .isEqualTo(
+ client.getErrorCodes().stream()
+ .map(SmsErrorCode::valueOf)
+ .collect(Collectors.toList()));
+ }
+
+ @Test
+ void convert() {
+ ScheduledProvisioningDto dto =
+ new ScheduledProvisioningDto(
+ "service plan id",
+ "campaign id",
+ OffsetDateTime.now(),
+ Collections.singletonList(SmsErrorCodeDto.ERROR_CODE_UNSPECIFIED))
+ .status(ProvisioningStatusDto.WAITING);
+
+ ScheduledSmsProvisioning converted = ScheduledSmsProvisioningDtoConverter.convert(dto);
+ compareWithDto(converted, dto);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledVoiceProvisioningDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledVoiceProvisioningDtoConverterTest.java
new file mode 100644
index 00000000..12259bdd
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/ScheduledVoiceProvisioningDtoConverterTest.java
@@ -0,0 +1,32 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.ScheduledVoiceProvisioning;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ProvisioningStatusDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ScheduledVoiceProvisioningDto;
+import java.time.OffsetDateTime;
+import org.junit.jupiter.api.Test;
+
+class ScheduledVoiceProvisioningDtoConverterTest {
+
+ public static void compareWithDto(
+ ScheduledVoiceProvisioning client, ScheduledVoiceProvisioningDto dto) {
+ if (null == client && null == dto) {
+ return;
+ }
+ assertEquals(dto.getAppId(), client.getAppId());
+ assertEquals(dto.getLastUpdatedTime().toInstant(), client.getLastUpdatedTime());
+ assertEquals(dto.getStatus().getValue(), client.getStatus().value());
+ }
+
+ @Test
+ void convert() {
+ ScheduledVoiceProvisioningDto dto =
+ new ScheduledVoiceProvisioningDto("app id", OffsetDateTime.now())
+ .status(ProvisioningStatusDto.WAITING);
+
+ ScheduledVoiceProvisioning converted = ScheduledVoiceProvisioningDtoConverter.convert(dto);
+ compareWithDto(converted, dto);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/SmsConfigurationDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/SmsConfigurationDtoConverterTest.java
new file mode 100644
index 00000000..2079b905
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/SmsConfigurationDtoConverterTest.java
@@ -0,0 +1,43 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.SMSConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ProvisioningStatusDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.SMSConfigurationDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ScheduledProvisioningDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.SmsErrorCodeDto;
+import java.time.OffsetDateTime;
+import java.util.Collections;
+import org.junit.jupiter.api.Test;
+
+class SmsConfigurationDtoConverterTest {
+
+ public static void compareWithDto(SMSConfiguration client, SMSConfigurationDto dto) {
+ if (null == client && null == dto) {
+ return;
+ }
+ assertEquals(dto.getServicePlanId(), client.getServicePlanId());
+ assertEquals(dto.getCampaignId(), client.getCampaignId().get());
+ ScheduledSmsProvisioningDtoConverterTest.compareWithDto(
+ client.getScheduledSmsProvisioning().get(), dto.getScheduledProvisioning());
+ }
+
+ @Test
+ void convert() {
+ SMSConfigurationDto dto =
+ new SMSConfigurationDto()
+ .servicePlanId("service plan id")
+ .campaignId("campaign id")
+ .scheduledProvisioning(
+ new ScheduledProvisioningDto(
+ "service plan id",
+ "campaign id",
+ OffsetDateTime.now(),
+ Collections.singletonList(SmsErrorCodeDto.ERROR_CODE_UNSPECIFIED))
+ .status(ProvisioningStatusDto.WAITING));
+
+ SMSConfiguration converted = SmsConfigurationDtoConverter.convert(dto);
+ compareWithDto(converted, dto);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/VoiceConfigurationDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/VoiceConfigurationDtoConverterTest.java
new file mode 100644
index 00000000..ea1352eb
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/adapters/converters/VoiceConfigurationDtoConverterTest.java
@@ -0,0 +1,36 @@
+package com.sinch.sdk.domains.numbers.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.sinch.sdk.domains.numbers.models.VoiceConfiguration;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ProvisioningStatusDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.ScheduledVoiceProvisioningDto;
+import com.sinch.sdk.domains.numbers.models.dto.v1.VoiceConfigurationDto;
+import java.time.OffsetDateTime;
+import org.junit.jupiter.api.Test;
+
+class VoiceConfigurationDtoConverterTest {
+
+ public static void compareWithDto(VoiceConfiguration client, VoiceConfigurationDto dto) {
+ if (null == client && null == dto) {
+ return;
+ }
+ assertEquals(dto.getAppId(), client.getAppId());
+ assertEquals(dto.getLastUpdatedTime().toInstant(), client.getLastUpdatedTime().get());
+ ScheduledVoiceProvisioningDtoConverterTest.compareWithDto(
+ client.getScheduledVoiceProvisioning().get(), dto.getScheduledVoiceProvisioning());
+ }
+
+ @Test
+ void convert() {
+ VoiceConfigurationDto dto =
+ new VoiceConfigurationDto(OffsetDateTime.now())
+ .appId("app id")
+ .scheduledVoiceProvisioning(
+ new ScheduledVoiceProvisioningDto("app id", OffsetDateTime.now())
+ .status(ProvisioningStatusDto.WAITING));
+
+ VoiceConfiguration converted = VoiceConfigurationDtoConverter.convert(dto);
+ compareWithDto(converted, dto);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/ActiveNumberBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/ActiveNumberBuilderTest.java
new file mode 100644
index 00000000..f3b0fa6b
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/ActiveNumberBuilderTest.java
@@ -0,0 +1,126 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ActiveNumberBuilderTest {
+
+ final String phoneNumber = "01234";
+ final String projectId = "project id";
+ final String displayName = "display name";
+ final String regionCode = "region";
+ final NumberType type = NumberType.MOBILE;
+ final Collection capability = Arrays.asList(Capability.VOICE, Capability.SMS);
+
+ final Money money = new Money("foo money", 0.50);
+
+ final Integer paymentIntervalMonths = 5;
+
+ final Instant nextChargeDate = Instant.now();
+
+ final Instant expireAt = Instant.now();
+
+ final SMSConfiguration smsConfiguration =
+ new SMSConfiguration(
+ "service plan id",
+ "campaign id",
+ new ScheduledSmsProvisioning(
+ "service plan id from scheduled",
+ "campaign id from scheduled",
+ ProvisioningStatus.FAILED,
+ Instant.now(),
+ Collections.singletonList(SmsErrorCode.ERROR_CODE_UNSPECIFIED)));
+ final VoiceConfiguration voiceConfiguration =
+ new VoiceConfiguration(
+ "app id",
+ Instant.now(),
+ new ScheduledVoiceProvisioning(
+ "app id from scheduled", ProvisioningStatus.IN_PROGRESS, Instant.now()));
+
+ final String callbackUrl = "foo callback";
+ final ActiveNumber value =
+ ActiveNumber.builder()
+ .setPhoneNumber(phoneNumber)
+ .setProjectId(projectId)
+ .setDisplayName(displayName)
+ .setRegionCode(regionCode)
+ .setType(type)
+ .setCapability(capability)
+ .setMoney(money)
+ .setPaymentIntervalMonths(paymentIntervalMonths)
+ .setNextChargeDate(nextChargeDate)
+ .setExpireAt(expireAt)
+ .setSmsConfiguration(smsConfiguration)
+ .setVoiceConfiguration(voiceConfiguration)
+ .setCallbackUrl(callbackUrl)
+ .build();
+
+ @Test
+ void getPhoneNumber() {
+ Assertions.assertThat(value.getPhoneNumber()).isEqualTo(phoneNumber);
+ }
+
+ @Test
+ void getProjectId() {
+ Assertions.assertThat(value.getProjectId()).isEqualTo(projectId);
+ }
+
+ @Test
+ void getDisplayName() {
+ Assertions.assertThat(value.getDisplayName()).isEqualTo(displayName);
+ }
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getCapability() {
+ Assertions.assertThat(value.getCapability()).usingRecursiveComparison().isEqualTo(capability);
+ }
+
+ @Test
+ void getMoney() {
+ Assertions.assertThat(value.getMoney()).isEqualTo(money);
+ }
+
+ @Test
+ void getPaymentIntervalMonths() {
+ Assertions.assertThat(value.getPaymentIntervalMonths()).isEqualTo(paymentIntervalMonths);
+ }
+
+ @Test
+ void getNextChargeDate() {
+ Assertions.assertThat(value.getNextChargeDate()).isEqualTo(nextChargeDate);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getSmsConfiguration() {
+ Assertions.assertThat(value.getSmsConfiguration()).isEqualTo(smsConfiguration);
+ }
+
+ @Test
+ void getVoiceConfiguration() {
+ Assertions.assertThat(value.getVoiceConfiguration()).isEqualTo(voiceConfiguration);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/ActiveNumberTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/ActiveNumberTest.java
new file mode 100644
index 00000000..a598ed46
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/ActiveNumberTest.java
@@ -0,0 +1,125 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ActiveNumberTest {
+
+ final String phoneNumber = "01234";
+ final String projectId = "project id";
+ final String displayName = "display name";
+ final String regionCode = "region";
+ final NumberType type = NumberType.MOBILE;
+ final Collection capability = Arrays.asList(Capability.VOICE, Capability.SMS);
+
+ final Money money = new Money("foo money", 0.50);
+
+ final Integer paymentIntervalMonths = 5;
+
+ final Instant nextChargeDate = Instant.now();
+
+ final Instant expireAt = Instant.now();
+
+ final SMSConfiguration smsConfiguration =
+ new SMSConfiguration(
+ "service plan id",
+ "campaign id",
+ new ScheduledSmsProvisioning(
+ "service plan id from scheduled",
+ "campaign id from scheduled",
+ ProvisioningStatus.FAILED,
+ Instant.now(),
+ Collections.singletonList(SmsErrorCode.ERROR_CODE_UNSPECIFIED)));
+ final VoiceConfiguration voiceConfiguration =
+ new VoiceConfiguration(
+ "app id",
+ Instant.now(),
+ new ScheduledVoiceProvisioning(
+ "app id from scheduled", ProvisioningStatus.IN_PROGRESS, Instant.now()));
+
+ final String callbackUrl = "foo callback";
+ final ActiveNumber value =
+ new ActiveNumber(
+ phoneNumber,
+ projectId,
+ displayName,
+ regionCode,
+ type,
+ capability,
+ money,
+ paymentIntervalMonths,
+ nextChargeDate,
+ expireAt,
+ smsConfiguration,
+ voiceConfiguration,
+ callbackUrl);
+
+ @Test
+ void getPhoneNumber() {
+ Assertions.assertThat(value.getPhoneNumber()).isEqualTo(phoneNumber);
+ }
+
+ @Test
+ void getProjectId() {
+ Assertions.assertThat(value.getProjectId()).isEqualTo(projectId);
+ }
+
+ @Test
+ void getDisplayName() {
+ Assertions.assertThat(value.getDisplayName()).isEqualTo(displayName);
+ }
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getCapability() {
+ Assertions.assertThat(value.getCapability()).usingRecursiveComparison().isEqualTo(capability);
+ }
+
+ @Test
+ void getMoney() {
+ Assertions.assertThat(value.getMoney()).isEqualTo(money);
+ }
+
+ @Test
+ void getPaymentIntervalMonths() {
+ Assertions.assertThat(value.getPaymentIntervalMonths()).isEqualTo(paymentIntervalMonths);
+ }
+
+ @Test
+ void getNextChargeDate() {
+ Assertions.assertThat(value.getNextChargeDate()).isEqualTo(nextChargeDate);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getSmsConfiguration() {
+ Assertions.assertThat(value.getSmsConfiguration()).isEqualTo(smsConfiguration);
+ }
+
+ @Test
+ void getVoiceConfiguration() {
+ Assertions.assertThat(value.getVoiceConfiguration()).isEqualTo(voiceConfiguration);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/AvailableNumberBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/AvailableNumberBuilderTest.java
new file mode 100644
index 00000000..c7016f86
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/AvailableNumberBuilderTest.java
@@ -0,0 +1,73 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberBuilderTest {
+
+ final String phoneNumber = "01234";
+ final String regionCode = "region";
+ final NumberType type = NumberType.MOBILE;
+ final Collection capability = Arrays.asList(Capability.VOICE, Capability.SMS);
+ final Money setupPrice = new Money("setup currency", .5);
+ final Money monthlyPrice = new Money("monthly currency", 1.5);
+ final Integer paymentIntervalMonths = 23;
+ final Boolean supportingDocumentationRequired = true;
+
+ final AvailableNumber value =
+ AvailableNumber.builder()
+ .setPhoneNumber(phoneNumber)
+ .setRegionCode(regionCode)
+ .setType(type)
+ .setCapability(capability)
+ .setSetupPrice(setupPrice)
+ .setMonthlyPrice(monthlyPrice)
+ .setPaymentIntervalMonths(paymentIntervalMonths)
+ .setSupportingDocumentationRequired(supportingDocumentationRequired)
+ .build();
+
+ @Test
+ void getPhoneNumber() {
+ Assertions.assertThat(value.getPhoneNumber()).isEqualTo(phoneNumber);
+ }
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getCapability() {
+ Assertions.assertThat(value.getCapability()).usingRecursiveComparison().isEqualTo(capability);
+ }
+
+ @Test
+ void getSetupPrice() {
+ Assertions.assertThat(value.getSetupPrice()).usingRecursiveComparison().isEqualTo(setupPrice);
+ }
+
+ @Test
+ void getMonthlyPrice() {
+ Assertions.assertThat(value.getMonthlyPrice())
+ .usingRecursiveComparison()
+ .isEqualTo(monthlyPrice);
+ }
+
+ @Test
+ void getPaymentIntervalMonths() {
+ Assertions.assertThat(value.getPaymentIntervalMonths()).isEqualTo(paymentIntervalMonths);
+ }
+
+ @Test
+ void getSupportingDocumentationRequired() {
+ Assertions.assertThat(value.getSupportingDocumentationRequired())
+ .isEqualTo(supportingDocumentationRequired);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/AvailableNumberTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/AvailableNumberTest.java
new file mode 100644
index 00000000..a72ba19d
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/AvailableNumberTest.java
@@ -0,0 +1,72 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberTest {
+
+ final String phoneNumber = "01234";
+ final String regionCode = "region";
+ final NumberType type = NumberType.MOBILE;
+ final Collection capability = Arrays.asList(Capability.VOICE, Capability.SMS);
+ final Money setupPrice = new Money("setup currency", .5);
+ final Money monthlyPrice = new Money("monthly currency", 1.5);
+ final Integer paymentIntervalMonths = 23;
+ final Boolean supportingDocumentationRequired = true;
+
+ final AvailableNumber value =
+ new AvailableNumber(
+ phoneNumber,
+ regionCode,
+ type,
+ capability,
+ setupPrice,
+ monthlyPrice,
+ paymentIntervalMonths,
+ supportingDocumentationRequired);
+
+ @Test
+ void getPhoneNumber() {
+ Assertions.assertThat(value.getPhoneNumber()).isEqualTo(phoneNumber);
+ }
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getCapability() {
+ Assertions.assertThat(value.getCapability()).usingRecursiveComparison().isEqualTo(capability);
+ }
+
+ @Test
+ void getSetupPrice() {
+ Assertions.assertThat(value.getSetupPrice()).usingRecursiveComparison().isEqualTo(setupPrice);
+ }
+
+ @Test
+ void getMonthlyPrice() {
+ Assertions.assertThat(value.getMonthlyPrice())
+ .usingRecursiveComparison()
+ .isEqualTo(monthlyPrice);
+ }
+
+ @Test
+ void getPaymentIntervalMonths() {
+ Assertions.assertThat(value.getPaymentIntervalMonths()).isEqualTo(paymentIntervalMonths);
+ }
+
+ @Test
+ void getSupportingDocumentationRequired() {
+ Assertions.assertThat(value.getSupportingDocumentationRequired())
+ .isEqualTo(supportingDocumentationRequired);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/CallbackConfigurationBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/CallbackConfigurationBuilderTest.java
new file mode 100644
index 00000000..cd4d0c32
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/CallbackConfigurationBuilderTest.java
@@ -0,0 +1,23 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class CallbackConfigurationBuilderTest {
+
+ final CallbackConfiguration value =
+ CallbackConfiguration.builder()
+ .setProjectId("project id")
+ .setHMACSecret("a HMAC secret")
+ .build();
+
+ @Test
+ void getProjectId() {
+ Assertions.assertThat(value.getProjectId()).isEqualTo("project id");
+ }
+
+ @Test
+ void getHMACSecret() {
+ Assertions.assertThat(value.getHMACSecret()).isEqualTo("a HMAC secret");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/CallbackConfigurationTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/CallbackConfigurationTest.java
new file mode 100644
index 00000000..85153ff6
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/CallbackConfigurationTest.java
@@ -0,0 +1,20 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class CallbackConfigurationTest {
+
+ final CallbackConfiguration value =
+ new CallbackConfiguration("the project id", "the secret HMAC");
+
+ @Test
+ void getProjectId() {
+ Assertions.assertThat(value.getProjectId()).isEqualTo("the project id");
+ }
+
+ @Test
+ void getHMACSecret() {
+ Assertions.assertThat(value.getHMACSecret()).isEqualTo("the secret HMAC");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/CapabilityTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/CapabilityTest.java
new file mode 100644
index 00000000..6aa0a3a3
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/CapabilityTest.java
@@ -0,0 +1,30 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class CapabilityTest {
+
+ final Capability newDefinedValue = Capability.from("foo");
+
+ @Test
+ void values() {
+ Assertions.assertThat(Capability.values()).contains(Capability.SMS);
+ }
+
+ @Test
+ void fromDefined() {
+ Assertions.assertThat(Capability.from("SMS")).isEqualTo(Capability.SMS);
+ }
+
+ @Test
+ void fromUndefined() {
+ Assertions.assertThat(newDefinedValue.value()).isEqualTo("foo");
+ Assertions.assertThat(Capability.values()).contains(newDefinedValue);
+ }
+
+ @Test
+ void valueOf() {
+ Assertions.assertThat(Capability.valueOf(newDefinedValue)).isEqualTo("foo");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/MoneyBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/MoneyBuilderTest.java
new file mode 100644
index 00000000..8a9822d4
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/MoneyBuilderTest.java
@@ -0,0 +1,19 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class MoneyBuilderTest {
+
+ final Money value = Money.builder().setAmount(.9).setCurrencyCode("currency").build();
+
+ @Test
+ void getCurrencyCode() {
+ Assertions.assertThat(value.getCurrencyCode()).isEqualTo("currency");
+ }
+
+ @Test
+ void getAmount() {
+ Assertions.assertThat(value.getAmount()).isEqualTo(.9);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/MoneyTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/MoneyTest.java
new file mode 100644
index 00000000..0b93a741
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/MoneyTest.java
@@ -0,0 +1,19 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class MoneyTest {
+
+ final Money value = new Money("currency", .9);
+
+ @Test
+ void getCurrencyCode() {
+ Assertions.assertThat(value.getCurrencyCode()).isEqualTo("currency");
+ }
+
+ @Test
+ void getAmount() {
+ Assertions.assertThat(value.getAmount()).isEqualTo(.9);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberPatternBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberPatternBuilderTest.java
new file mode 100644
index 00000000..c0217d77
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberPatternBuilderTest.java
@@ -0,0 +1,22 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class NumberPatternBuilderTest {
+ final NumberPattern value =
+ NumberPattern.builder()
+ .setPattern("a pattern")
+ .setSearchPattern(SearchPattern.CONTAINS)
+ .build();
+
+ @Test
+ void getPattern() {
+ Assertions.assertThat(value.getPattern()).isEqualTo("a pattern");
+ }
+
+ @Test
+ void getSearchPattern() {
+ Assertions.assertThat(value.getSearchPattern()).isEqualTo(SearchPattern.CONTAINS);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberPatternTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberPatternTest.java
new file mode 100644
index 00000000..9d46994b
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberPatternTest.java
@@ -0,0 +1,18 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class NumberPatternTest {
+ final NumberPattern value = new NumberPattern("a pattern", SearchPattern.CONTAINS);
+
+ @Test
+ void getPattern() {
+ Assertions.assertThat(value.getPattern()).isEqualTo("a pattern");
+ }
+
+ @Test
+ void getSearchPattern() {
+ Assertions.assertThat(value.getSearchPattern()).isEqualTo(SearchPattern.CONTAINS);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberTypeTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberTypeTest.java
new file mode 100644
index 00000000..5b9f5bd9
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/NumberTypeTest.java
@@ -0,0 +1,29 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class NumberTypeTest {
+ final NumberType newDefinedValue = NumberType.from("foo");
+
+ @Test
+ void values() {
+ Assertions.assertThat(NumberType.values()).contains(NumberType.LOCAL);
+ }
+
+ @Test
+ void fromDefined() {
+ Assertions.assertThat(NumberType.from("LOCAL")).isEqualTo(NumberType.LOCAL);
+ }
+
+ @Test
+ void fromUndefined() {
+ Assertions.assertThat(newDefinedValue.value()).isEqualTo("foo");
+ Assertions.assertThat(NumberType.values()).contains(newDefinedValue);
+ }
+
+ @Test
+ void valueOf() {
+ Assertions.assertThat(NumberType.valueOf(newDefinedValue)).isEqualTo("foo");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/RegionBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/RegionBuilderTest.java
new file mode 100644
index 00000000..852e46d0
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/RegionBuilderTest.java
@@ -0,0 +1,28 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.util.Collection;
+import java.util.Collections;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class RegionBuilderTest {
+
+ Collection types = Collections.singletonList(NumberType.TOLL_FREE);
+ final Region value =
+ Region.builder().setRegionCode("foo code").setRegionName("foo name").setTypes(types).build();
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo("foo code");
+ }
+
+ @Test
+ void getRegionName() {
+ Assertions.assertThat(value.getRegionName()).isEqualTo("foo name");
+ }
+
+ @Test
+ void getTypes() {
+ Assertions.assertThat(value.getTypes()).usingRecursiveComparison().isEqualTo(types);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/RegionTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/RegionTest.java
new file mode 100644
index 00000000..de19a947
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/RegionTest.java
@@ -0,0 +1,27 @@
+package com.sinch.sdk.domains.numbers.models;
+
+import java.util.Collection;
+import java.util.Collections;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class RegionTest {
+
+ Collection types = Collections.singletonList(NumberType.TOLL_FREE);
+ final Region value = new Region("foo code", "foo name", types);
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo("foo code");
+ }
+
+ @Test
+ void getRegionName() {
+ Assertions.assertThat(value.getRegionName()).isEqualTo("foo name");
+ }
+
+ @Test
+ void getTypes() {
+ Assertions.assertThat(value.getTypes()).usingRecursiveComparison().isEqualTo(types);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParametersBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParametersBuilderTest.java
new file mode 100644
index 00000000..3254ae4a
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParametersBuilderTest.java
@@ -0,0 +1,70 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.*;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ActiveNumberListRequestParametersBuilderTest {
+
+ final String regionCode = "foo region";
+ final NumberType type = NumberType.MOBILE;
+ final NumberPattern numberPattern =
+ NumberPattern.builder().setPattern("a pattern").setSearchPattern(SearchPattern.END).build();
+ final Collection capabilities = Arrays.asList(Capability.VOICE, Capability.SMS);
+ final Integer pageSize = 45;
+
+ final String pageToken = "page token";
+
+ final OrderBy orderBy = OrderBy.PHONE_NUMBER;
+ final ActiveNumberListRequestParameters value =
+ ActiveNumberListRequestParameters.builder()
+ .setRegionCode(regionCode)
+ .setType(type)
+ .setNumberPattern(numberPattern)
+ .setCapabilities(capabilities)
+ .setPageSize(pageSize)
+ .setPageToken(pageToken)
+ .setOrderBy(orderBy)
+ .build();
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getNumberPattern() {
+ Assertions.assertThat(value.getNumberPattern().get())
+ .usingRecursiveComparison()
+ .isEqualTo(numberPattern);
+ }
+
+ @Test
+ void getCapabilities() {
+ Assertions.assertThat(value.getCapabilities().get())
+ .usingRecursiveComparison()
+ .isEqualTo(capabilities);
+ }
+
+ @Test
+ void getPageSize() {
+ Assertions.assertThat(value.getPageSize().get()).isEqualTo(pageSize);
+ }
+
+ @Test
+ void getPageToken() {
+ Assertions.assertThat(value.getPageToken().get()).isEqualTo(pageToken);
+ }
+
+ @Test
+ void getOrderBy() {
+ Assertions.assertThat(value.getOrderBy().get()).isEqualTo(orderBy);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParametersTest.java
new file mode 100644
index 00000000..eb7fe1df
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/ActiveNumberListRequestParametersTest.java
@@ -0,0 +1,64 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.*;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ActiveNumberListRequestParametersTest {
+
+ static final String regionCode = "foo region";
+ static final NumberType type = NumberType.MOBILE;
+ static final NumberPattern numberPattern = new NumberPattern("a pattern", SearchPattern.END);
+ static final Collection capabilities =
+ Arrays.asList(Capability.VOICE, Capability.SMS);
+ static final Integer pageSize = 45;
+
+ static final String pageToken = "page token";
+
+ static final OrderBy orderBy = OrderBy.PHONE_NUMBER;
+
+ public static final ActiveNumberListRequestParameters value =
+ new ActiveNumberListRequestParameters(
+ regionCode, type, numberPattern, capabilities, pageSize, pageToken, orderBy);
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getNumberPattern() {
+ Assertions.assertThat(value.getNumberPattern().get())
+ .usingRecursiveComparison()
+ .isEqualTo(numberPattern);
+ }
+
+ @Test
+ void getCapabilities() {
+ Assertions.assertThat(value.getCapabilities().get())
+ .usingRecursiveComparison()
+ .isEqualTo(capabilities);
+ }
+
+ @Test
+ void getPageSize() {
+ Assertions.assertThat(value.getPageSize().get()).isEqualTo(pageSize);
+ }
+
+ @Test
+ void getPageToken() {
+ Assertions.assertThat(value.getPageToken().get()).isEqualTo(pageToken);
+ }
+
+ @Test
+ void getOrderBy() {
+ Assertions.assertThat(value.getOrderBy().get()).isEqualTo(orderBy);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParametersBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParametersBuilderTest.java
new file mode 100644
index 00000000..b210d89a
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParametersBuilderTest.java
@@ -0,0 +1,58 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.SearchPattern;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberListAllRequestParametersBuilderTest {
+
+ final String regionCode = "foo region";
+ final NumberType type = NumberType.MOBILE;
+ final NumberPattern numberPattern =
+ NumberPattern.builder().setPattern("a pattern").setSearchPattern(SearchPattern.END).build();
+ final Collection capabilities = Arrays.asList(Capability.VOICE, Capability.SMS);
+ final Integer size = 145;
+
+ final AvailableNumberListAllRequestParameters value =
+ AvailableNumberListAllRequestParameters.builder()
+ .setRegionCode(regionCode)
+ .setType(type)
+ .setNumberPattern(numberPattern)
+ .setCapabilities(capabilities)
+ .setSize(size)
+ .build();
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getNumberPattern() {
+ Assertions.assertThat(value.getNumberPattern().get())
+ .usingRecursiveComparison()
+ .isEqualTo(numberPattern);
+ }
+
+ @Test
+ void getCapabilities() {
+ Assertions.assertThat(value.getCapabilities().get())
+ .usingRecursiveComparison()
+ .isEqualTo(capabilities);
+ }
+
+ @Test
+ void getSize() {
+ Assertions.assertThat(value.getSize().get()).isEqualTo(size);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParametersTest.java
new file mode 100644
index 00000000..267e8f09
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberListAllRequestParametersTest.java
@@ -0,0 +1,52 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.SearchPattern;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberListAllRequestParametersTest {
+
+ final String regionCode = "foo region";
+ final NumberType type = NumberType.MOBILE;
+ final NumberPattern numberPattern = new NumberPattern("a pattern", SearchPattern.END);
+ final Collection capabilities = Arrays.asList(Capability.VOICE, Capability.SMS);
+ final Integer size = 145;
+
+ final AvailableNumberListAllRequestParameters value =
+ new AvailableNumberListAllRequestParameters(
+ regionCode, type, numberPattern, capabilities, size);
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).usingRecursiveComparison().isEqualTo(type);
+ }
+
+ @Test
+ void getNumberPattern() {
+ Assertions.assertThat(value.getNumberPattern().get())
+ .usingRecursiveComparison()
+ .isEqualTo(numberPattern);
+ }
+
+ @Test
+ void getCapabilities() {
+ Assertions.assertThat(value.getCapabilities().get())
+ .usingRecursiveComparison()
+ .isEqualTo(capabilities);
+ }
+
+ @Test
+ void getSize() {
+ Assertions.assertThat(value.getSize().get()).isEqualTo(size);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersAnyBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersAnyBuilderTest.java
new file mode 100644
index 00000000..619565df
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersAnyBuilderTest.java
@@ -0,0 +1,76 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.SearchPattern;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberRentRequestParametersAnyBuilderTest {
+
+ final String regionCode = "foo region";
+ final NumberType type = NumberType.MOBILE;
+ final NumberPattern numberPattern =
+ NumberPattern.builder().setPattern("a pattern").setSearchPattern(SearchPattern.END).build();
+ final Collection capabilities = Arrays.asList(Capability.VOICE, Capability.SMS);
+
+ final RentSMSConfigurationRequestParameters smsConfiguration =
+ RentSMSConfigurationRequestParameters.builder()
+ .setServicePlanId("plan id")
+ .setCampaignId("campaign id")
+ .build();
+
+ final RentVoiceConfigurationRequestParameters voiceConfiguration =
+ RentVoiceConfigurationRequestParameters.builder().setAppId("app id").build();
+ final String callbackUrl = " the callback";
+
+ final AvailableNumberRentAnyRequestParameters value =
+ AvailableNumberRentAnyRequestParameters.builder()
+ .setRegionCode(regionCode)
+ .setType(type)
+ .setNumberPattern(numberPattern)
+ .setCapabilities(capabilities)
+ .setSmsConfiguration(smsConfiguration)
+ .setVoiceConfiguration(voiceConfiguration)
+ .setCallbackUrl(callbackUrl)
+ .build();
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).isEqualTo(type);
+ }
+
+ @Test
+ void getNumberPattern() {
+ Assertions.assertThat(value.getNumberPattern()).isEqualTo(Optional.of(numberPattern));
+ }
+
+ @Test
+ void getCapabilities() {
+ Assertions.assertThat(value.getCapabilities()).isEqualTo(Optional.of(capabilities));
+ }
+
+ @Test
+ void getSmsConfiguration() {
+ Assertions.assertThat(value.getSmsConfiguration()).isEqualTo(Optional.of(smsConfiguration));
+ }
+
+ @Test
+ void getVoiceConfiguration() {
+ Assertions.assertThat(value.getVoiceConfiguration()).isEqualTo(Optional.of(voiceConfiguration));
+ }
+
+ @Test
+ void getCallBackUrl() {
+ Assertions.assertThat(value.getCallBackUrl()).isEqualTo(Optional.of(callbackUrl));
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersAnyTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersAnyTest.java
new file mode 100644
index 00000000..56618791
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersAnyTest.java
@@ -0,0 +1,71 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.NumberPattern;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.SearchPattern;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberRentRequestParametersAnyTest {
+
+ final String regionCode = "foo region";
+ final NumberType type = NumberType.MOBILE;
+ final NumberPattern numberPattern = new NumberPattern("a pattern", SearchPattern.END);
+ final Collection capabilities = Arrays.asList(Capability.VOICE, Capability.SMS);
+
+ final RentSMSConfigurationRequestParameters smsConfiguration =
+ new RentSMSConfigurationRequestParameters("plan id", "campaign id");
+
+ final RentVoiceConfigurationRequestParameters voiceConfiguration =
+ new RentVoiceConfigurationRequestParameters("app id");
+ final String callbackUrl = " the callback";
+
+ final AvailableNumberRentAnyRequestParameters value =
+ new AvailableNumberRentAnyRequestParameters(
+ regionCode,
+ type,
+ numberPattern,
+ capabilities,
+ smsConfiguration,
+ voiceConfiguration,
+ callbackUrl);
+
+ @Test
+ void getRegionCode() {
+ Assertions.assertThat(value.getRegionCode()).isEqualTo(regionCode);
+ }
+
+ @Test
+ void getType() {
+ Assertions.assertThat(value.getType()).isEqualTo(type);
+ }
+
+ @Test
+ void getNumberPattern() {
+ Assertions.assertThat(value.getNumberPattern()).isEqualTo(Optional.of(numberPattern));
+ }
+
+ @Test
+ void getCapabilities() {
+ Assertions.assertThat(value.getCapabilities()).isEqualTo(Optional.of(capabilities));
+ }
+
+ @Test
+ void getSmsConfiguration() {
+ Assertions.assertThat(value.getSmsConfiguration()).isEqualTo(Optional.of(smsConfiguration));
+ }
+
+ @Test
+ void getVoiceConfiguration() {
+ Assertions.assertThat(value.getVoiceConfiguration()).isEqualTo(Optional.of(voiceConfiguration));
+ }
+
+ @Test
+ void getCallBackUrl() {
+ Assertions.assertThat(value.getCallBackUrl()).isEqualTo(Optional.of(callbackUrl));
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersBuilderTest.java
new file mode 100644
index 00000000..85f4d8b1
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersBuilderTest.java
@@ -0,0 +1,40 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import java.util.Optional;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberRentRequestParametersBuilderTest {
+
+ RentSMSConfigurationRequestParameters smsConfiguration =
+ RentSMSConfigurationRequestParameters.builder()
+ .setServicePlanId("plan id")
+ .setCampaignId("campaign id")
+ .build();
+
+ RentVoiceConfigurationRequestParameters voiceConfiguration =
+ RentVoiceConfigurationRequestParameters.builder().setAppId("app id").build();
+ String callbackUrl = "the callback";
+
+ final AvailableNumberRentRequestParameters value =
+ AvailableNumberRentRequestParameters.builder()
+ .setSmsConfiguration(smsConfiguration)
+ .setVoiceConfiguration(voiceConfiguration)
+ .setCallbackUrl(callbackUrl)
+ .build();
+
+ @Test
+ void getSmsConfiguration() {
+ Assertions.assertThat(value.getSmsConfiguration()).isEqualTo(Optional.of(smsConfiguration));
+ }
+
+ @Test
+ void getVoiceConfiguration() {
+ Assertions.assertThat(value.getVoiceConfiguration()).isEqualTo(Optional.of(voiceConfiguration));
+ }
+
+ @Test
+ void getCallBackUrl() {
+ Assertions.assertThat(value.getCallBackUrl()).isEqualTo(Optional.of(callbackUrl));
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersTest.java
new file mode 100644
index 00000000..4ee7d1fe
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableNumberRentRequestParametersTest.java
@@ -0,0 +1,33 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import java.util.Optional;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberRentRequestParametersTest {
+
+ RentSMSConfigurationRequestParameters smsConfiguration =
+ new RentSMSConfigurationRequestParameters("plan id", "campaign id");
+
+ RentVoiceConfigurationRequestParameters voiceConfiguration =
+ new RentVoiceConfigurationRequestParameters("app id");
+ String callbackUrl = "the callback";
+
+ final AvailableNumberRentRequestParameters value =
+ new AvailableNumberRentRequestParameters(smsConfiguration, voiceConfiguration, callbackUrl);
+
+ @Test
+ void getSmsConfiguration() {
+ Assertions.assertThat(value.getSmsConfiguration()).isEqualTo(Optional.of(smsConfiguration));
+ }
+
+ @Test
+ void getVoiceConfiguration() {
+ Assertions.assertThat(value.getVoiceConfiguration()).isEqualTo(Optional.of(voiceConfiguration));
+ }
+
+ @Test
+ void getCallBackUrl() {
+ Assertions.assertThat(value.getCallBackUrl()).isEqualTo(Optional.of(callbackUrl));
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParametersBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParametersBuilderTest.java
new file mode 100644
index 00000000..2edc31e6
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParametersBuilderTest.java
@@ -0,0 +1,20 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableRegionListAllRequestParametersBuilderTest {
+
+ final Collection types = Arrays.asList(NumberType.MOBILE, NumberType.TOLL_FREE);
+
+ final AvailableRegionListAllRequestParameters value =
+ AvailableRegionListAllRequestParameters.builder().setTypes(types).build();
+
+ @Test
+ void getTypes() {
+ Assertions.assertThat(value.getTypes().get()).usingRecursiveComparison().isEqualTo(types);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParametersTest.java
new file mode 100644
index 00000000..be0185be
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/AvailableRegionListAllRequestParametersTest.java
@@ -0,0 +1,20 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableRegionListAllRequestParametersTest {
+
+ final Collection types = Arrays.asList(NumberType.MOBILE, NumberType.TOLL_FREE);
+
+ final AvailableRegionListAllRequestParameters value =
+ new AvailableRegionListAllRequestParameters(types);
+
+ @Test
+ void getTypes() {
+ Assertions.assertThat(value.getTypes().get()).usingRecursiveComparison().isEqualTo(types);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParametersBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParametersBuilderTest.java
new file mode 100644
index 00000000..9cd046a8
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParametersBuilderTest.java
@@ -0,0 +1,15 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class CallbackConfigurationUpdateRequestParametersBuilderTest {
+
+ final CallbackConfigurationUpdateRequestParameters value =
+ CallbackConfigurationUpdateRequestParameters.builder().setHMACSecret("hmac value").build();
+
+ @Test
+ void getHMACSecret() {
+ Assertions.assertThat(value.getHMACSecret()).isEqualTo("hmac value");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParametersTest.java
new file mode 100644
index 00000000..b315a5c6
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/CallbackConfigurationUpdateRequestParametersTest.java
@@ -0,0 +1,15 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class CallbackConfigurationUpdateRequestParametersTest {
+
+ final CallbackConfigurationUpdateRequestParameters value =
+ new CallbackConfigurationUpdateRequestParameters("hmac value");
+
+ @Test
+ void getHMACSecret() {
+ Assertions.assertThat(value.getHMACSecret()).isEqualTo("hmac value");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParametersBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParametersBuilderTest.java
new file mode 100644
index 00000000..33a8f53f
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParametersBuilderTest.java
@@ -0,0 +1,31 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import java.util.Optional;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class RentSMSConfigurationRequestParametersBuilderTest {
+ RentSMSConfigurationRequestParameters value =
+ RentSMSConfigurationRequestParameters.builder()
+ .setServicePlanId("plan id")
+ .setCampaignId("campaign id")
+ .build();
+
+ RentSMSConfigurationRequestParameters valueNoCampaign =
+ RentSMSConfigurationRequestParameters.builder().setServicePlanId("plan id").build();
+
+ @Test
+ void getServicePlanId() {
+ Assertions.assertThat(value.getServicePlanId()).isEqualTo("plan id");
+ }
+
+ @Test
+ void getCampaignId() {
+ Assertions.assertThat(value.getCampaignId()).isEqualTo(Optional.of("campaign id"));
+ }
+
+ @Test
+ void geCampaignIdEmpty() {
+ Assertions.assertThat(valueNoCampaign.getCampaignId()).isEqualTo(Optional.empty());
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParametersTest.java
new file mode 100644
index 00000000..fb1c1a1b
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentSMSConfigurationRequestParametersTest.java
@@ -0,0 +1,28 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import java.util.Optional;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class RentSMSConfigurationRequestParametersTest {
+ RentSMSConfigurationRequestParameters value =
+ new RentSMSConfigurationRequestParameters("plan id", "campaign id");
+
+ RentSMSConfigurationRequestParameters valueNoCampaign =
+ new RentSMSConfigurationRequestParameters("plan id");
+
+ @Test
+ void getServicePlanId() {
+ Assertions.assertThat(value.getServicePlanId()).isEqualTo("plan id");
+ }
+
+ @Test
+ void getCampaignId() {
+ Assertions.assertThat(value.getCampaignId()).isEqualTo(Optional.of("campaign id"));
+ }
+
+ @Test
+ void geCampaignIdEmpty() {
+ Assertions.assertThat(valueNoCampaign.getCampaignId()).isEqualTo(Optional.empty());
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParametersBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParametersBuilderTest.java
new file mode 100644
index 00000000..dca37cbd
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParametersBuilderTest.java
@@ -0,0 +1,15 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class RentVoiceConfigurationRequestParametersBuilderTest {
+
+ RentVoiceConfigurationRequestParameters value =
+ RentVoiceConfigurationRequestParameters.builder().setAppId("app id").build();
+
+ @Test
+ void getAppId() {
+ Assertions.assertThat(value.getAppId()).isEqualTo("app id");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParametersTest.java
new file mode 100644
index 00000000..73205ac0
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/requests/RentVoiceConfigurationRequestParametersTest.java
@@ -0,0 +1,15 @@
+package com.sinch.sdk.domains.numbers.models.requests;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class RentVoiceConfigurationRequestParametersTest {
+
+ RentVoiceConfigurationRequestParameters value =
+ new RentVoiceConfigurationRequestParameters("app id");
+
+ @Test
+ void getAppId() {
+ Assertions.assertThat(value.getAppId()).isEqualTo("app id");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/ActiveNumberListResponseTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/ActiveNumberListResponseTest.java
new file mode 100644
index 00000000..e1525191
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/ActiveNumberListResponseTest.java
@@ -0,0 +1,153 @@
+package com.sinch.sdk.domains.numbers.models.responses;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.models.pagination.Page;
+import com.sinch.sdk.core.models.pagination.PageToken;
+import com.sinch.sdk.domains.numbers.ActiveNumberService;
+import com.sinch.sdk.domains.numbers.models.*;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberListRequestParameters;
+import com.sinch.sdk.domains.numbers.models.requests.ActiveNumberListRequestParametersTest;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+
+class ActiveNumberListResponseTest extends BaseTest {
+ @Mock ActiveNumberService service;
+
+ List list =
+ Stream.generate(
+ () ->
+ ActiveNumber.builder()
+ .setPhoneNumber(String.valueOf(Math.random()))
+ .setProjectId(String.valueOf(Math.random()))
+ .setDisplayName(String.valueOf(Math.random()))
+ .setRegionCode(String.valueOf(Math.random()))
+ .setType(NumberType.from(String.valueOf(Math.random())))
+ .setCapability(Arrays.asList(Capability.VOICE, Capability.SMS))
+ .setMoney(new Money(String.valueOf(Math.random()), Math.random()))
+ .setPaymentIntervalMonths((int) (Math.random() * 12))
+ .setNextChargeDate(
+ Instant.ofEpochMilli(ThreadLocalRandom.current().nextLong()))
+ .setExpireAt(Instant.ofEpochMilli(ThreadLocalRandom.current().nextLong()))
+ .setSmsConfiguration(
+ new SMSConfiguration(
+ String.valueOf(Math.random()),
+ String.valueOf(Math.random()),
+ new ScheduledSmsProvisioning(
+ String.valueOf(Math.random()),
+ String.valueOf(Math.random()),
+ ProvisioningStatus.FAILED,
+ Instant.ofEpochMilli(ThreadLocalRandom.current().nextLong()),
+ Collections.singletonList(SmsErrorCode.ERROR_CODE_UNSPECIFIED))))
+ .setVoiceConfiguration(
+ new VoiceConfiguration(
+ String.valueOf(Math.random()),
+ Instant.ofEpochMilli(ThreadLocalRandom.current().nextLong()),
+ new ScheduledVoiceProvisioning(
+ String.valueOf(Math.random()),
+ ProvisioningStatus.IN_PROGRESS,
+ Instant.ofEpochMilli(ThreadLocalRandom.current().nextLong()))))
+ .setCallbackUrl(String.valueOf(Math.random()))
+ .build())
+ .limit(13)
+ .collect(Collectors.toList());
+
+ List> pages =
+ Arrays.asList(
+ new Page<>(
+ ActiveNumberListRequestParametersTest.value,
+ list.stream().limit(5).collect(Collectors.toList()),
+ new PageToken<>("foo page2")),
+ new Page<>(
+ ActiveNumberListRequestParametersTest.value,
+ list.stream().skip(5).limit(5).collect(Collectors.toList()),
+ new PageToken<>("foo page3")),
+ new Page<>(
+ ActiveNumberListRequestParametersTest.value,
+ list.stream().skip(10).collect(Collectors.toList()),
+ null));
+
+ @Test
+ void autoPageIter() {
+ setupMockedService();
+ AtomicInteger count = new AtomicInteger();
+ ActiveNumberListResponse response = new ActiveNumberListResponse(service, pages.get(0));
+ response
+ .autoPageIter()
+ .forEachRemaining(
+ value -> {
+ Assertions.assertThat(value)
+ .usingRecursiveComparison()
+ .isEqualTo(list.get(count.get()));
+ count.getAndIncrement();
+ });
+ assertEquals(count.get(), list.size());
+ }
+
+ @Test
+ void hasNextPage() {
+
+ ActiveNumberListResponse response = new ActiveNumberListResponse(service, pages.get(0));
+ assertTrue(response.hasNextPage());
+ response = new ActiveNumberListResponse(service, pages.get(1));
+ assertTrue(response.hasNextPage());
+ response = new ActiveNumberListResponse(service, pages.get(2));
+ assertFalse(response.hasNextPage());
+ }
+
+ @Test
+ void nextPage() {
+
+ setupMockedService();
+ ActiveNumberListResponse response = new ActiveNumberListResponse(service, pages.get(0));
+ int page = 1;
+ while (response.hasNextPage()) {
+ response = response.nextPage();
+ Assertions.assertThat(response.getContent())
+ .usingRecursiveComparison()
+ .isEqualTo(pages.get(page).getEntities());
+ page++;
+ }
+ assertThrows(NoSuchElementException.class, response::nextPage);
+ }
+
+ @Test
+ void getContent() {
+
+ for (Page page : pages) {
+ ActiveNumberListResponse response = new ActiveNumberListResponse(service, page);
+ Assertions.assertThat(response.getContent())
+ .usingRecursiveComparison()
+ .isEqualTo(page.getEntities());
+ }
+ }
+
+ void setupMockedService() {
+ when(service.list(any(ActiveNumberListRequestParameters.class)))
+ .thenAnswer(
+ invocation -> {
+ ActiveNumberListRequestParameters parameters =
+ invocation.getArgument(0, ActiveNumberListRequestParameters.class);
+ switch (parameters.getPageToken().get()) {
+ case "foo page2":
+ return new ActiveNumberListResponse(service, pages.get(1));
+ case "foo page3":
+ return new ActiveNumberListResponse(service, pages.get(2));
+ }
+ return null;
+ });
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/AvailableNumberListResponseTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/AvailableNumberListResponseTest.java
new file mode 100644
index 00000000..40baa359
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/AvailableNumberListResponseTest.java
@@ -0,0 +1,69 @@
+package com.sinch.sdk.domains.numbers.models.responses;
+
+import static java.lang.String.valueOf;
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.sinch.sdk.domains.numbers.models.AvailableNumber;
+import com.sinch.sdk.domains.numbers.models.Capability;
+import com.sinch.sdk.domains.numbers.models.Money;
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableNumberListResponseTest {
+
+ List list =
+ Stream.generate(
+ () ->
+ AvailableNumber.builder()
+ .setPhoneNumber(valueOf(Math.random()))
+ .setRegionCode(valueOf(Math.random()))
+ .setType(NumberType.LOCAL)
+ .setCapability(Collections.singletonList(Capability.VOICE))
+ .setSetupPrice(new Money(valueOf(Math.random()), Math.random() * 100))
+ .setMonthlyPrice(new Money(valueOf(Math.random()), Math.random() * 100))
+ .setPaymentIntervalMonths((int) (Math.random() * 12))
+ .setSupportingDocumentationRequired(true)
+ .build())
+ .limit(15)
+ .collect(Collectors.toList());
+
+ AvailableNumberListResponse response = new AvailableNumberListResponse(new ArrayList<>(list));
+
+ @Test
+ void autoPageIter() {
+ AtomicInteger count = new AtomicInteger();
+ response
+ .autoPageIter()
+ .forEachRemaining(
+ value -> {
+ Assertions.assertThat(value)
+ .usingRecursiveComparison()
+ .isEqualTo(list.get(count.get()));
+ count.getAndIncrement();
+ });
+ assertEquals(count.get(), list.size());
+ }
+
+ @Test
+ void hasNextPage() {
+ assertFalse(response.hasNextPage(), "Has no next page");
+ }
+
+ @Test
+ void nextPage() {
+ assertThrows(NoSuchElementException.class, response::nextPage);
+ }
+
+ @Test
+ void getContent() {
+ Assertions.assertThat(response.getContent()).usingRecursiveComparison().isEqualTo(list);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/AvailableRegionListResponseTest.java b/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/AvailableRegionListResponseTest.java
new file mode 100644
index 00000000..ff4e04b7
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/numbers/models/responses/AvailableRegionListResponseTest.java
@@ -0,0 +1,61 @@
+package com.sinch.sdk.domains.numbers.models.responses;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.sinch.sdk.domains.numbers.models.NumberType;
+import com.sinch.sdk.domains.numbers.models.Region;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class AvailableRegionListResponseTest {
+
+ List list =
+ Stream.generate(
+ () ->
+ Region.builder()
+ .setRegionCode(String.valueOf(Math.random()))
+ .setRegionName(String.valueOf(Math.random()))
+ .setTypes(Collections.singletonList(NumberType.TOLL_FREE))
+ .build())
+ .limit(15)
+ .collect(Collectors.toList());
+
+ AvailableRegionListResponse response = new AvailableRegionListResponse(new ArrayList<>(list));
+
+ @Test
+ void autoPageIter() {
+ AtomicInteger count = new AtomicInteger();
+ response
+ .autoPageIter()
+ .forEachRemaining(
+ value -> {
+ Assertions.assertThat(value)
+ .usingRecursiveComparison()
+ .isEqualTo(list.get(count.get()));
+ count.getAndIncrement();
+ });
+ assertEquals(count.get(), list.size());
+ }
+
+ @Test
+ void hasNextPage() {
+ assertFalse(response.hasNextPage(), "Has no next page");
+ }
+
+ @Test
+ void nextPage() {
+ assertThrows(NoSuchElementException.class, response::nextPage);
+ }
+
+ @Test
+ void getContent() {
+ Assertions.assertThat(response.getContent()).usingRecursiveComparison().isEqualTo(list);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/adapters/BatchesServiceTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/adapters/BatchesServiceTest.java
new file mode 100644
index 00000000..4a9ed4e0
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/adapters/BatchesServiceTest.java
@@ -0,0 +1,169 @@
+package com.sinch.sdk.domains.sms.adapters;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.utils.Pair;
+import com.sinch.sdk.domains.sms.adapters.api.v1.BatchesApi;
+import com.sinch.sdk.domains.sms.models.*;
+import com.sinch.sdk.domains.sms.models.dto.v1.ParameterObjDto;
+import com.sinch.sdk.domains.sms.models.dto.v1.ParameterObjParameterKeyDto;
+import com.sinch.sdk.domains.sms.models.dto.v1.SendSMS201ResponseDto;
+import com.sinch.sdk.models.Configuration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+
+@TestWithResources
+public class BatchesServiceTest extends BaseTest {
+
+ final String id = "01FC66621XXXXX119Z8PMV1QPQ";
+ final Collection to = Arrays.asList("+15551231234", "+15551256344");
+ final String from = "+15551231234";
+ final boolean canceled = false;
+ final Instant createdAt = Instant.parse("2019-08-24T14:15:22Z");
+ final Instant modifiedAt = Instant.parse("2019-08-24T14:17:22Z");
+ final DeliveryReport deliveryReport = DeliveryReport.NONE;
+ final Instant sendAt = Instant.parse("2019-08-24T14:19:22Z");
+ final Instant expireAt = Instant.parse("2019-08-24T14:21:22Z");
+ final String callbackUrl = "callback url";
+ final String clientReference = "myReference";
+ final boolean flashMessage = true;
+ final boolean feedbackEnabled = false;
+ final boolean truncateConcat = true;
+ final int maxNumberOfMessageParts = 1;
+ final int fromTon = 6;
+ final int fromNpi = 18;
+ final String udh = "foo udh";
+ final String body = "Hi ${name}! How are you?";
+ public final BatchBinary batchBinary =
+ BatchBinary.builder()
+ .setId(id)
+ .setTo(to)
+ .setFrom(from)
+ .setCanceled(canceled)
+ .setBody(body)
+ .setCreatedAt(createdAt)
+ .setModifiedAt(modifiedAt)
+ .setDeliveryReport(deliveryReport)
+ .setSendAt(sendAt)
+ .setExpireAt(expireAt)
+ .setCallbackUrl(callbackUrl)
+ .setClientReference(clientReference)
+ .setFlashMessage(flashMessage)
+ .setFeedbackEnabled(feedbackEnabled)
+ .setTruncateConcat(truncateConcat)
+ .setMaxNumberOfMessageParts(maxNumberOfMessageParts)
+ .setFromTon(fromTon)
+ .setFromNpi(fromNpi)
+ .setUdh(udh)
+ .build();
+ final Parameters parameters =
+ new Parameters(
+ Arrays.asList(
+ new Parameters.Entry("an identifier", new Pair<>("a key", "a value")),
+ new Parameters.Entry(
+ ParameterObjDto
+ .JSON_PROPERTY_LEFT_CURLY_BRACKET_PARAMETER_KEY_RIGHT_CURLY_BRACKET,
+ new Pair<>(
+ ParameterObjParameterKeyDto
+ .JSON_PROPERTY_LEFT_CURLY_BRACKET_MSISDN_RIGHT_CURLY_BRACKET,
+ "msisdn value"),
+ "default value")));
+ public final BatchMedia batchMedia =
+ BatchMedia.builder()
+ .setId(id)
+ .setTo(to)
+ .setFrom(from)
+ .setCanceled(canceled)
+ .setBody(
+ new MediaBody(
+ "https://en.wikipedia.org/wiki/Sinch_(company)#/media/File:Sinch_LockUp_RGB.png",
+ "Media message from Sinch!"))
+ .setCreatedAt(Instant.parse("2019-08-24T14:14:22Z"))
+ .setModifiedAt(Instant.parse("2019-08-24T14:15:22Z"))
+ .setDeliveryReport(DeliveryReport.SUMMARY)
+ .setSendAt(Instant.parse("2019-08-24T14:16:22Z"))
+ .setExpireAt(Instant.parse("2019-08-24T14:17:22Z"))
+ .setCallbackUrl(callbackUrl)
+ .setClientReference("client reference")
+ .setFeedbackEnabled(feedbackEnabled)
+ .setParameters(parameters)
+ .build();
+ public final BatchText batchText =
+ BatchText.builder()
+ .setId(id)
+ .setTo(to)
+ .setFrom(from)
+ .setCanceled(canceled)
+ .setBody(body)
+ .setCreatedAt(createdAt)
+ .setModifiedAt(modifiedAt)
+ .setDeliveryReport(deliveryReport)
+ .setSendAt(sendAt)
+ .setExpireAt(expireAt)
+ .setCallbackUrl(callbackUrl)
+ .setClientReference(clientReference)
+ .setFlashMessage(flashMessage)
+ .setFeedbackEnabled(feedbackEnabled)
+ .setTruncateConcat(truncateConcat)
+ .setMaxNumberOfMessageParts(maxNumberOfMessageParts)
+ .setFromTon(fromTon)
+ .setFromNpi(fromNpi)
+ .setParameters(parameters)
+ .build();
+
+ @GivenJsonResource("/domains/sms/v1/BinaryResponseDto.json")
+ public SendSMS201ResponseDto binaryResponseDto;
+
+ @GivenJsonResource("/domains/sms/v1/MediaResponseDto.json")
+ SendSMS201ResponseDto mediaResponseDto;
+
+ @GivenJsonResource("/domains/sms/v1/TextResponseDto.json")
+ SendSMS201ResponseDto textResponseDto;
+
+ @Mock Configuration configuration;
+ @Mock BatchesApi api;
+ @InjectMocks BatchesService service;
+
+ @Test
+ void getBinary() throws ApiException {
+
+ when(api.getBatchMessage(eq(configuration.getProjectId()), eq("foo binary batch id")))
+ .thenReturn(binaryResponseDto);
+
+ Batch> response = service.get("foo binary batch id");
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(batchBinary);
+ }
+
+ @Test
+ void getMedia() throws ApiException {
+
+ when(api.getBatchMessage(eq(configuration.getProjectId()), eq("foo media batch id")))
+ .thenReturn(mediaResponseDto);
+
+ Batch> response = service.get("foo media batch id");
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(batchMedia);
+ }
+
+ @Test
+ void getText() throws ApiException {
+
+ when(api.getBatchMessage(eq(configuration.getProjectId()), eq("foo text batch id")))
+ .thenReturn(textResponseDto);
+
+ Batch> response = service.get("foo text batch id");
+
+ Assertions.assertThat(response).usingRecursiveComparison().isEqualTo(batchText);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/adapters/converters/BatchDtoConverterTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/adapters/converters/BatchDtoConverterTest.java
new file mode 100644
index 00000000..ded49e62
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/adapters/converters/BatchDtoConverterTest.java
@@ -0,0 +1,145 @@
+package com.sinch.sdk.domains.sms.adapters.converters;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import com.adelean.inject.resources.junit.jupiter.GivenJsonResource;
+import com.adelean.inject.resources.junit.jupiter.TestWithResources;
+import com.sinch.sdk.BaseTest;
+import com.sinch.sdk.core.utils.Pair;
+import com.sinch.sdk.domains.sms.models.*;
+import com.sinch.sdk.domains.sms.models.dto.v1.*;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@TestWithResources
+class BatchDtoConverterTest extends BaseTest {
+
+ @GivenJsonResource("/domains/sms/v1/BinaryResponseDto.json")
+ public SendSMS201ResponseDto binaryResponseDto;
+
+ @GivenJsonResource("/domains/sms/v1/TextResponseDto.json")
+ public SendSMS201ResponseDto textResponseDto;
+
+ @GivenJsonResource("/domains/sms/v1/MediaResponseDto.json")
+ public SendSMS201ResponseDto mediaResponseDto;
+
+ public static void compareWithDto(Batch> client, SendSMS201ResponseDto dto) {
+ Object obj = dto.getActualInstance();
+ if (obj instanceof BinaryResponseDto) {
+ assertInstanceOf(BatchBinary.class, client);
+ compareBinary((BatchBinary) client, dto.getBinaryResponseDto());
+ } else if (obj instanceof MediaResponseDto) {
+ assertInstanceOf(BatchMedia.class, client);
+ compareMedia((BatchMedia) client, dto.getMediaResponseDto());
+ } else if (obj instanceof TextResponseDto) {
+ assertInstanceOf(BatchText.class, client);
+ compareText((BatchText) client, dto.getTextResponseDto());
+ } else {
+ fail("Unexpected class:" + obj.getClass().getName());
+ }
+ }
+
+ private static void compareBinary(BatchBinary client, BinaryResponseDto dto) {
+ assertEquals(dto.getId(), client.getId());
+ assertEquals(dto.getTo(), client.getTo());
+ assertEquals(dto.getFrom(), client.getFrom());
+ assertEquals(dto.getCanceled(), client.isCanceled());
+ assertEquals(dto.getBody(), client.getBody());
+ assertEquals(dto.getUdh(), client.getUdh());
+ assertEquals(dto.getType(), BinaryResponseDto.TypeEnum.MT_BINARY.getValue());
+ assertEquals(dto.getCreatedAt().toInstant(), client.getCreatedAt());
+ assertEquals(dto.getModifiedAt().toInstant(), client.getModifiedAt());
+ Assertions.assertEquals(dto.getDeliveryReport(), client.getDeliveryReport().value());
+ assertEquals(dto.getSendAt().toInstant(), client.getSendAt());
+ assertEquals(dto.getExpireAt().toInstant(), client.getExpireAt());
+ assertEquals(dto.getCallbackUrl(), client.getCallbackUrl());
+ assertEquals(dto.getClientReference(), client.getClientReference());
+ assertEquals(dto.getFeedbackEnabled(), client.isFeedbackEnabled());
+ assertEquals(dto.getFlashMessage(), client.isFlashMessage());
+ assertEquals(dto.getTruncateConcat(), client.isTruncateConcat());
+ assertEquals(dto.getMaxNumberOfMessageParts(), client.getMaxNumberOfMessageParts());
+ assertEquals(dto.getFromTon(), client.getFromTon());
+ assertEquals(dto.getFromNpi(), client.getFromNpi());
+ }
+
+ private static void compareMedia(BatchMedia client, MediaResponseDto dto) {
+ assertEquals(dto.getId(), client.getId());
+ assertEquals(dto.getTo(), client.getTo());
+ assertEquals(dto.getFrom(), client.getFrom());
+ assertEquals(dto.getCanceled(), client.isCanceled());
+ assertEquals(dto.getBody().getMessage(), client.getBody().getMessage());
+ assertEquals(dto.getBody().getUrl(), client.getBody().getUrl());
+ assertEquals(dto.getType(), MediaResponseDto.TypeEnum.MT_MEDIA.getValue());
+ assertEquals(dto.getCreatedAt().toInstant(), client.getCreatedAt());
+ assertEquals(dto.getModifiedAt().toInstant(), client.getModifiedAt());
+ Assertions.assertEquals(dto.getDeliveryReport(), client.getDeliveryReport().value());
+ assertEquals(dto.getSendAt().toInstant(), client.getSendAt());
+ assertEquals(dto.getExpireAt().toInstant(), client.getExpireAt());
+ compareParameters(client.getParameters(), dto.getParameters());
+ assertEquals(dto.getCallbackUrl(), client.getCallbackUrl());
+ assertEquals(dto.getClientReference(), client.getClientReference());
+ assertEquals(dto.getFeedbackEnabled(), client.isFeedbackEnabled());
+ }
+
+ private static void compareText(BatchText client, TextResponseDto dto) {
+ assertEquals(dto.getId(), client.getId());
+ assertEquals(dto.getTo(), client.getTo());
+ assertEquals(dto.getFrom(), client.getFrom());
+ assertEquals(dto.getCanceled(), client.isCanceled());
+ assertEquals(dto.getBody(), client.getBody());
+ assertEquals(dto.getType(), TextResponseDto.TypeEnum.MT_TEXT.getValue());
+ assertEquals(dto.getCreatedAt().toInstant(), client.getCreatedAt());
+ assertEquals(dto.getModifiedAt().toInstant(), client.getModifiedAt());
+ Assertions.assertEquals(dto.getDeliveryReport(), client.getDeliveryReport().value());
+ assertEquals(dto.getSendAt().toInstant(), client.getSendAt());
+ assertEquals(dto.getExpireAt().toInstant(), client.getExpireAt());
+ assertEquals(dto.getCallbackUrl(), client.getCallbackUrl());
+ assertEquals(dto.getClientReference(), client.getClientReference());
+ assertEquals(dto.getFeedbackEnabled(), client.isFeedbackEnabled());
+ assertEquals(dto.getFlashMessage(), client.isFlashMessage());
+ assertEquals(dto.getTruncateConcat(), client.isTruncateConcat());
+ compareParameters(client.getParameters(), dto.getParameters());
+ assertEquals(dto.getMaxNumberOfMessageParts(), client.getMaxNumberOfMessageParts());
+ assertEquals(dto.getFromTon(), client.getFromTon());
+ assertEquals(dto.getFromNpi(), client.getFromNpi());
+ }
+
+ private static void compareParameters(Parameters client, ParameterObjDto dto) {
+ assertEquals(dto.size(), client.size());
+ Collection values = client.values();
+ values.forEach(
+ e -> {
+ Pair clientItem = e.getValue();
+ assertTrue(dto.containsKey(e.getKey()));
+ @SuppressWarnings("unchecked")
+ Map dtoItem = (Map) dto.get(e.getKey());
+ assertTrue(dtoItem.containsKey(clientItem.getLeft()));
+ assertEquals(dtoItem.get(clientItem.getLeft()), clientItem.getRight());
+ Optional defaultValue = e.getDefaultValue();
+ if (defaultValue.isPresent()) {
+ assertEquals(
+ dtoItem.get(ParameterObjParameterKeyDto.JSON_PROPERTY_DEFAULT), defaultValue.get());
+ } else {
+ assertNull(dtoItem.get(ParameterObjParameterKeyDto.JSON_PROPERTY_DEFAULT));
+ }
+ });
+ }
+
+ @Test
+ void convertBinary() {
+ compareWithDto(BatchDtoConverter.convert(binaryResponseDto), binaryResponseDto);
+ }
+
+ @Test
+ void convertMedia() {
+ compareWithDto(BatchDtoConverter.convert(mediaResponseDto), mediaResponseDto);
+ }
+
+ @Test
+ void convertText() {
+ compareWithDto(BatchDtoConverter.convert(textResponseDto), textResponseDto);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBinaryBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBinaryBuilderTest.java
new file mode 100644
index 00000000..4ad146da
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBinaryBuilderTest.java
@@ -0,0 +1,143 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchBinaryBuilderTest {
+
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+ final Instant createdAt = Instant.now();
+ final Instant modifiedAt = Instant.now();
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+ final Instant sendAt = Instant.now();
+ final Instant expireAt = Instant.now();
+ final String callbackUrl = "callback value";
+ final String clientReference = " client reference";
+ final boolean feedbackEnabled = false;
+ final boolean truncateConcat = true;
+ final int maxNumberOfMessageParts = 23;
+ final int fromTon = 1234;
+ final int fromNpi = 567;
+ final String udh = "udh value";
+ final String body = "body content";
+ final BatchBinary value =
+ BatchBinary.builder()
+ .setId(id)
+ .setTo(to)
+ .setFrom(from)
+ .setCanceled(canceled)
+ .setBody(body)
+ .setCreatedAt(createdAt)
+ .setModifiedAt(modifiedAt)
+ .setDeliveryReport(deliveryReport)
+ .setSendAt(sendAt)
+ .setExpireAt(expireAt)
+ .setCallbackUrl(callbackUrl)
+ .setClientReference(clientReference)
+ .setFeedbackEnabled(feedbackEnabled)
+ .setTruncateConcat(truncateConcat)
+ .setMaxNumberOfMessageParts(maxNumberOfMessageParts)
+ .setFromTon(fromTon)
+ .setFromNpi(fromNpi)
+ .setUdh(udh)
+ .build();
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+
+ @Test
+ void isTruncateConcat() {
+ Assertions.assertThat(value.isTruncateConcat()).isEqualTo(truncateConcat);
+ }
+
+ @Test
+ void getMaxNumberOfMessageParts() {
+ Assertions.assertThat(value.getMaxNumberOfMessageParts()).isEqualTo(maxNumberOfMessageParts);
+ }
+
+ @Test
+ void getFromTon() {
+ Assertions.assertThat(value.getFromTon()).isEqualTo(fromTon);
+ }
+
+ @Test
+ void getFromNpi() {
+ Assertions.assertThat(value.getFromNpi()).isEqualTo(fromNpi);
+ }
+
+ @Test
+ void getUdh() {
+ Assertions.assertThat(value.getUdh()).isEqualTo(udh);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBinaryTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBinaryTest.java
new file mode 100644
index 00000000..2f782047
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBinaryTest.java
@@ -0,0 +1,144 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchBinaryTest {
+
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+ final Instant createdAt = Instant.now();
+ final Instant modifiedAt = Instant.now();
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+ final Instant sendAt = Instant.now();
+ final Instant expireAt = Instant.now();
+ final String callbackUrl = "callback value";
+ final String clientReference = " client reference";
+ final boolean flashMessage = true;
+ final boolean feedbackEnabled = false;
+ final boolean truncateConcat = true;
+ final int maxNumberOfMessageParts = 23;
+ final int fromTon = 1234;
+ final int fromNpi = 567;
+ final String udh = "udh value";
+ final String body = "body content";
+ final BatchBinary value =
+ new BatchBinary(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled,
+ flashMessage,
+ truncateConcat,
+ maxNumberOfMessageParts,
+ fromTon,
+ fromNpi,
+ udh);
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+
+ @Test
+ void isTruncateConcat() {
+ Assertions.assertThat(value.isTruncateConcat()).isEqualTo(truncateConcat);
+ }
+
+ @Test
+ void getMaxNumberOfMessageParts() {
+ Assertions.assertThat(value.getMaxNumberOfMessageParts()).isEqualTo(maxNumberOfMessageParts);
+ }
+
+ @Test
+ void getFromTon() {
+ Assertions.assertThat(value.getFromTon()).isEqualTo(fromTon);
+ }
+
+ @Test
+ void getFromNpi() {
+ Assertions.assertThat(value.getFromNpi()).isEqualTo(fromNpi);
+ }
+
+ @Test
+ void getUdh() {
+ Assertions.assertThat(value.getUdh()).isEqualTo(udh);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBuilderTest.java
new file mode 100644
index 00000000..5a8927c9
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchBuilderTest.java
@@ -0,0 +1,118 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchBuilderTest {
+
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+
+ final Integer body = -45;
+
+ final Instant createdAt = Instant.now();
+
+ final Instant modifiedAt = Instant.now();
+
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+
+ final Instant sendAt = Instant.now();
+
+ final Instant expireAt = Instant.now();
+
+ final String callbackUrl = "callback value";
+
+ final String clientReference = " client reference";
+
+ final boolean feedbackEnabled = false;
+
+ final Batch value =
+ Batch.batchBuilder()
+ .setId(id)
+ .setTo(to)
+ .setFrom(from)
+ .setCanceled(canceled)
+ .setBody(body)
+ .setCreatedAt(createdAt)
+ .setModifiedAt(modifiedAt)
+ .setDeliveryReport(deliveryReport)
+ .setSendAt(sendAt)
+ .setExpireAt(expireAt)
+ .setCallbackUrl(callbackUrl)
+ .setClientReference(clientReference)
+ .setFeedbackEnabled(feedbackEnabled)
+ .build();
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchMediaBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchMediaBuilderTest.java
new file mode 100644
index 00000000..a7692241
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchMediaBuilderTest.java
@@ -0,0 +1,124 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchMediaBuilderTest {
+
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+ final Parameters parameters = null;
+ final Instant createdAt = Instant.now();
+ final Instant modifiedAt = Instant.now();
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+ final Instant sendAt = Instant.now();
+ final Instant expireAt = Instant.now();
+ final String callbackUrl = "callback value";
+ final String clientReference = " client reference";
+ final boolean feedbackEnabled = false;
+
+ final MediaBody body = new MediaBody("body message", "url value");
+ final boolean strictValidation = true;
+
+ final BatchMedia value =
+ BatchMedia.builder()
+ .setId(id)
+ .setTo(to)
+ .setFrom(from)
+ .setCanceled(canceled)
+ .setBody(body)
+ .setParameters(parameters)
+ .setCreatedAt(createdAt)
+ .setModifiedAt(modifiedAt)
+ .setDeliveryReport(deliveryReport)
+ .setSendAt(sendAt)
+ .setExpireAt(expireAt)
+ .setCallbackUrl(callbackUrl)
+ .setClientReference(clientReference)
+ .setFeedbackEnabled(feedbackEnabled)
+ .setStrictValidation(strictValidation)
+ .build();
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getParameters() {
+ Assertions.assertThat(value.getParameters()).isEqualTo(parameters);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+
+ @Test
+ void isStrictValidation() {
+ Assertions.assertThat(value.isStrictValidation()).isEqualTo(strictValidation);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchMediaTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchMediaTest.java
new file mode 100644
index 00000000..2d11b321
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchMediaTest.java
@@ -0,0 +1,126 @@
+package com.sinch.sdk.domains.sms.models;
+
+import com.sinch.sdk.core.utils.Pair;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchMediaTest {
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+ final Parameters parameters =
+ new Parameters(
+ Arrays.asList(
+ new Parameters.Entry("key 1", new Pair<>("value identifier1", "value 1")),
+ new Parameters.Entry(
+ "key 2", new Pair<>("value identifier2", "value 2"), "default value for ")));
+ final Instant createdAt = Instant.now();
+ final Instant modifiedAt = Instant.now();
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+ final Instant sendAt = Instant.now();
+ final Instant expireAt = Instant.now();
+ final String callbackUrl = "callback value";
+ final String clientReference = " client reference";
+ final boolean feedbackEnabled = false;
+ final MediaBody body = new MediaBody("url value", "body message");
+ final boolean strictValidation = true;
+ final BatchMedia value =
+ new BatchMedia(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled,
+ parameters,
+ strictValidation);
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getParameters() {
+ Assertions.assertThat(value.getParameters()).usingRecursiveComparison().isEqualTo(parameters);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+
+ @Test
+ void isStrictValidation() {
+ Assertions.assertThat(value.isStrictValidation()).isEqualTo(strictValidation);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTest.java
new file mode 100644
index 00000000..5cd68c60
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTest.java
@@ -0,0 +1,117 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchTest {
+
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+
+ final Integer body = -45;
+
+ final Instant createdAt = Instant.now();
+
+ final Instant modifiedAt = Instant.now();
+
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+
+ final Instant sendAt = Instant.now();
+
+ final Instant expireAt = Instant.now();
+
+ final String callbackUrl = "callback value";
+
+ final String clientReference = " client reference";
+
+ final boolean feedbackEnabled = false;
+
+ final Batch value =
+ new Batch<>(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ feedbackEnabled);
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTextBuilderTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTextBuilderTest.java
new file mode 100644
index 00000000..2d5ff3fa
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTextBuilderTest.java
@@ -0,0 +1,143 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchTextBuilderTest {
+
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+ final Parameters parameters = null;
+ final Instant createdAt = Instant.now();
+ final Instant modifiedAt = Instant.now();
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+ final Instant sendAt = Instant.now();
+ final Instant expireAt = Instant.now();
+ final String callbackUrl = "callback value";
+ final String clientReference = " client reference";
+ final boolean feedbackEnabled = false;
+ final boolean truncateConcat = true;
+ final int maxNumberOfMessageParts = 23;
+ final int fromTon = 1234;
+ final int fromNpi = 567;
+ final String body = "body content";
+ final BatchText value =
+ BatchText.builder()
+ .setId(id)
+ .setTo(to)
+ .setFrom(from)
+ .setCanceled(canceled)
+ .setBody(body)
+ .setCreatedAt(createdAt)
+ .setModifiedAt(modifiedAt)
+ .setDeliveryReport(deliveryReport)
+ .setSendAt(sendAt)
+ .setExpireAt(expireAt)
+ .setCallbackUrl(callbackUrl)
+ .setClientReference(clientReference)
+ .setFeedbackEnabled(feedbackEnabled)
+ .setTruncateConcat(truncateConcat)
+ .setMaxNumberOfMessageParts(maxNumberOfMessageParts)
+ .setFromTon(fromTon)
+ .setFromNpi(fromNpi)
+ .setParameters(parameters)
+ .build();
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getParameters() {
+ Assertions.assertThat(value.getParameters()).isEqualTo(parameters);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+
+ @Test
+ void isTruncateConcat() {
+ Assertions.assertThat(value.isTruncateConcat()).isEqualTo(truncateConcat);
+ }
+
+ @Test
+ void getMaxNumberOfMessageParts() {
+ Assertions.assertThat(value.getMaxNumberOfMessageParts()).isEqualTo(maxNumberOfMessageParts);
+ }
+
+ @Test
+ void getFromTon() {
+ Assertions.assertThat(value.getFromTon()).isEqualTo(fromTon);
+ }
+
+ @Test
+ void getFromNpi() {
+ Assertions.assertThat(value.getFromNpi()).isEqualTo(fromNpi);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTextTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTextTest.java
new file mode 100644
index 00000000..89847d15
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/BatchTextTest.java
@@ -0,0 +1,144 @@
+package com.sinch.sdk.domains.sms.models;
+
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collection;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class BatchTextTest {
+
+ final String id = "an id";
+
+ final Collection to = Arrays.asList("to1", "to2");
+
+ final String from = "from value";
+
+ final boolean canceled = true;
+ final Parameters parameters = null;
+ final Instant createdAt = Instant.now();
+ final Instant modifiedAt = Instant.now();
+ final DeliveryReport deliveryReport = DeliveryReport.FULL;
+ final Instant sendAt = Instant.now();
+ final Instant expireAt = Instant.now();
+ final String callbackUrl = "callback value";
+ final String clientReference = " client reference";
+ final boolean flashMessage = true;
+ final boolean feedbackEnabled = false;
+ final boolean truncateConcat = true;
+ final int maxNumberOfMessageParts = 23;
+ final int fromTon = 1234;
+ final int fromNpi = 567;
+ final String body = "body content";
+ final BatchText value =
+ new BatchText(
+ id,
+ to,
+ from,
+ canceled,
+ body,
+ createdAt,
+ modifiedAt,
+ deliveryReport,
+ sendAt,
+ expireAt,
+ callbackUrl,
+ clientReference,
+ flashMessage,
+ feedbackEnabled,
+ parameters,
+ truncateConcat,
+ maxNumberOfMessageParts,
+ fromTon,
+ fromNpi);
+
+ @Test
+ void getId() {
+ Assertions.assertThat(value.getId()).isEqualTo(id);
+ }
+
+ @Test
+ void getTo() {
+ Assertions.assertThat(value.getTo()).usingRecursiveComparison().isEqualTo(to);
+ }
+
+ @Test
+ void getFrom() {
+ Assertions.assertThat(value.getFrom()).isEqualTo(from);
+ }
+
+ @Test
+ void isCanceled() {
+ Assertions.assertThat(value.isCanceled()).isEqualTo(canceled);
+ }
+
+ @Test
+ void getBody() {
+ Assertions.assertThat(value.getBody()).isEqualTo(body);
+ }
+
+ @Test
+ void getParameters() {
+ Assertions.assertThat(value.getParameters()).isEqualTo(parameters);
+ }
+
+ @Test
+ void getExpireAt() {
+ Assertions.assertThat(value.getExpireAt()).isEqualTo(expireAt);
+ }
+
+ @Test
+ void getCreatedAt() {
+ Assertions.assertThat(value.getCreatedAt()).isEqualTo(createdAt);
+ }
+
+ @Test
+ void getModifiedAt() {
+ Assertions.assertThat(value.getModifiedAt()).isEqualTo(modifiedAt);
+ }
+
+ @Test
+ void getDeliveryReport() {
+ Assertions.assertThat(value.getDeliveryReport()).isEqualTo(deliveryReport);
+ }
+
+ @Test
+ void getSendAt() {
+ Assertions.assertThat(value.getSendAt()).isEqualTo(sendAt);
+ }
+
+ @Test
+ void getCallbackUrl() {
+ Assertions.assertThat(value.getCallbackUrl()).isEqualTo(callbackUrl);
+ }
+
+ @Test
+ void getClientReference() {
+ Assertions.assertThat(value.getClientReference()).isEqualTo(clientReference);
+ }
+
+ @Test
+ void isFeedbackEnabled() {
+ Assertions.assertThat(value.isFeedbackEnabled()).isEqualTo(feedbackEnabled);
+ }
+
+ @Test
+ void isTruncateConcat() {
+ Assertions.assertThat(value.isTruncateConcat()).isEqualTo(truncateConcat);
+ }
+
+ @Test
+ void getMaxNumberOfMessageParts() {
+ Assertions.assertThat(value.getMaxNumberOfMessageParts()).isEqualTo(maxNumberOfMessageParts);
+ }
+
+ @Test
+ void getFromTon() {
+ Assertions.assertThat(value.getFromTon()).isEqualTo(fromTon);
+ }
+
+ @Test
+ void getFromNpi() {
+ Assertions.assertThat(value.getFromNpi()).isEqualTo(fromNpi);
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/MediaBodyTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/MediaBodyTest.java
new file mode 100644
index 00000000..bf1a3cd3
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/MediaBodyTest.java
@@ -0,0 +1,19 @@
+package com.sinch.sdk.domains.sms.models;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class MediaBodyTest {
+
+ final MediaBody value = new MediaBody("the url", "the message");
+
+ @Test
+ void getMessage() {
+ Assertions.assertThat(value.getMessage()).isEqualTo("the message");
+ }
+
+ @Test
+ void getUrl() {
+ Assertions.assertThat(value.getUrl()).isEqualTo("the url");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/domains/sms/models/ParametersTest.java b/client/src/test/java/com/sinch/sdk/domains/sms/models/ParametersTest.java
new file mode 100644
index 00000000..638607f5
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/domains/sms/models/ParametersTest.java
@@ -0,0 +1,28 @@
+package com.sinch.sdk.domains.sms.models;
+
+import com.sinch.sdk.core.utils.Pair;
+import java.util.Arrays;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ParametersTest {
+ final Parameters parameters =
+ new Parameters(
+ Arrays.asList(
+ new Parameters.Entry("key 1", new Pair<>("value identifier1", "value 1")),
+ new Parameters.Entry(
+ "key 2", new Pair<>("value identifier2", "value 2"), "default value for ")));
+
+ @Test
+ void getParameters() {
+ Assertions.assertThat(parameters.get("key 1"))
+ .usingRecursiveComparison()
+ .isEqualTo(new Parameters.Entry("key 1", new Pair<>("value identifier1", "value 1")));
+
+ Assertions.assertThat(parameters.get("key 2"))
+ .usingRecursiveComparison()
+ .isEqualTo(
+ new Parameters.Entry(
+ "key 2", new Pair<>("value identifier2", "value 2"), "default value for "));
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/models/ConfigurationBuilderTest.java b/client/src/test/java/com/sinch/sdk/models/ConfigurationBuilderTest.java
new file mode 100644
index 00000000..345f6750
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/models/ConfigurationBuilderTest.java
@@ -0,0 +1,41 @@
+package com.sinch.sdk.models;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ConfigurationBuilderTest {
+ static final String KEY = "fooKey";
+ static final String SECRET = "fooSecret";
+ static final String PROJECT = "fooProject";
+ static final String OAUTH_URL = "foo oauth url";
+ static final String NUMBERS_SERVER = "fooNUMBERS_SERVER";
+ static final SMSRegion SMS_REGION = SMSRegion.AU;
+ static final String SMS_SERVER = "%sfooSMS_SERVER";
+
+ @Test
+ void build() {
+ Configuration value =
+ new Configuration.Builder()
+ .setKeyId(KEY)
+ .setKeySecret(SECRET)
+ .setProjectId(PROJECT)
+ .setOAuthUrl(OAUTH_URL)
+ .setNumbersUrl(NUMBERS_SERVER)
+ .setSmsRegion(SMS_REGION)
+ .setSmsUrl(SMS_SERVER)
+ .build();
+ assertEquals(KEY, value.getKeyId());
+ assertEquals(SECRET, value.getKeySecret());
+ assertEquals(PROJECT, value.getProjectId());
+ Assertions.assertEquals(OAUTH_URL, value.getOAuthServer().getUrl());
+ Assertions.assertEquals(NUMBERS_SERVER, value.getNumbersServer().getUrl());
+ Assertions.assertTrue(
+ value.getSmsServer().getUrl().contains(SMS_REGION.value()),
+ "SMS Region present within SMS server URL");
+ Assertions.assertTrue(
+ value.getSmsServer().getUrl().contains("fooSMS_SERVER"),
+ "SMS server present within SMS server URL");
+ }
+}
diff --git a/client/src/test/java/com/sinch/sdk/models/ConfigurationTest.java b/client/src/test/java/com/sinch/sdk/models/ConfigurationTest.java
new file mode 100644
index 00000000..aa3ee650
--- /dev/null
+++ b/client/src/test/java/com/sinch/sdk/models/ConfigurationTest.java
@@ -0,0 +1,63 @@
+package com.sinch.sdk.models;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+class ConfigurationTest {
+ static final String KEY = "fooKey";
+ static final String SECRET = "fooSecret";
+ static final String PROJECT = "fooProject";
+ static final String OAUTH_URL = "foo oauth url";
+ static final String NUMBERS_SERVER = "fooNUMBERS_SERVER";
+ static final SMSRegion SMS_REGION = SMSRegion.AU;
+ static final String SMS_SERVER = "%sfooSMS_SERVER";
+
+ static final Configuration configuration =
+ new Configuration.Builder()
+ .setKeyId(KEY)
+ .setKeySecret(SECRET)
+ .setProjectId(PROJECT)
+ .setOAuthUrl(OAUTH_URL)
+ .setNumbersUrl(NUMBERS_SERVER)
+ .setSmsRegion(SMS_REGION)
+ .setSmsUrl(SMS_SERVER)
+ .build();
+
+ @Test
+ void testToString() {
+ String value = configuration.toString();
+ assertFalse(value.contains(KEY), "Config should not contains 'key' value");
+ assertFalse(value.contains(SECRET), "Config should not contains 'secret' value");
+ assertFalse(value.contains(PROJECT), "Config should not contains 'project' value");
+ }
+
+ @Test
+ void getKeyId() {
+ assertEquals(KEY, configuration.getKeyId());
+ }
+
+ @Test
+ void getKeySecret() {
+ assertEquals(SECRET, configuration.getKeySecret());
+ }
+
+ @Test
+ void getProjectId() {
+ assertEquals(PROJECT, configuration.getProjectId());
+ }
+
+ @Test
+ void defaultUSForSmSRegion() {
+ Configuration configuration =
+ new Configuration.Builder()
+ .setKeyId(KEY)
+ .setKeySecret(SECRET)
+ .setProjectId(PROJECT)
+ .setOAuthUrl(OAUTH_URL)
+ .setNumbersUrl(NUMBERS_SERVER)
+ .setSmsUrl(SMS_SERVER)
+ .build();
+ assertEquals(configuration.getSmsRegion(), SMSRegion.US);
+ }
+}
diff --git a/client/src/test/resources/client/auth/BearerAuthResponse.json b/client/src/test/resources/client/auth/BearerAuthResponse.json
new file mode 100644
index 00000000..2b4acac1
--- /dev/null
+++ b/client/src/test/resources/client/auth/BearerAuthResponse.json
@@ -0,0 +1,6 @@
+{
+ "access_token": "token value",
+ "expires_in": 123456,
+ "scope": "scope value",
+ "token_type": "token type value"
+}
diff --git a/core/src/main/com/sinch/sdk/core/exceptions/ApiAuthException.java b/core/src/main/com/sinch/sdk/core/exceptions/ApiAuthException.java
new file mode 100644
index 00000000..7f202431
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/exceptions/ApiAuthException.java
@@ -0,0 +1,20 @@
+package com.sinch.sdk.core.exceptions;
+
+import com.sinch.sdk.core.http.HttpStatus;
+
+public class ApiAuthException extends ApiException {
+
+ private static final long serialVersionUID = -1L;
+
+ public ApiAuthException(Throwable throwable) {
+ super(null, throwable, HttpStatus.UNAUTHORIZED);
+ }
+
+ public ApiAuthException(String message) {
+ super(message, null, HttpStatus.UNAUTHORIZED);
+ }
+
+ public ApiAuthException(int code, String message) {
+ super(message, null, code);
+ }
+}
diff --git a/core/src/main/com/sinch/sdk/core/exceptions/ApiException.java b/core/src/main/com/sinch/sdk/core/exceptions/ApiException.java
new file mode 100644
index 00000000..d7b31989
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/exceptions/ApiException.java
@@ -0,0 +1,44 @@
+package com.sinch.sdk.core.exceptions;
+
+public class ApiException extends RuntimeException {
+
+ private static final long serialVersionUID = -1L;
+ private int code = 0;
+
+ public ApiException() {}
+
+ public ApiException(Throwable throwable) {
+ super(throwable);
+ }
+
+ public ApiException(String message) {
+ super(message);
+ }
+
+ public ApiException(String message, Throwable throwable, int code) {
+ super(message, throwable);
+ this.code = code;
+ }
+
+ public ApiException(String message, int code) {
+ this(message, null, code);
+ }
+
+ public ApiException(int code, String message) {
+ this(message, null, code);
+ }
+
+ /**
+ * Get the HTTP status code.
+ *
+ * @return HTTP status code
+ */
+ public int getCode() {
+ return code;
+ }
+
+ @Override
+ public String toString() {
+ return "ApiException{" + "code=" + code + ", message=" + super.getMessage();
+ }
+}
diff --git a/core/src/main/com/sinch/sdk/core/exceptions/ApiExceptionBuilder.java b/core/src/main/com/sinch/sdk/core/exceptions/ApiExceptionBuilder.java
new file mode 100644
index 00000000..8f5ecccf
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/exceptions/ApiExceptionBuilder.java
@@ -0,0 +1,57 @@
+package com.sinch.sdk.core.exceptions;
+
+import java.util.Map;
+import java.util.Optional;
+
+public class ApiExceptionBuilder {
+
+ public static ApiException build(String message, int code) {
+ return new ApiException(message, code);
+ }
+
+ public static ApiException build(String message, int code, Map mappedResponse) {
+
+ // Hardcoded Numbers API errors like format parsing
+ Optional numbersException = getExceptionFromNumbersOrSmsError(mappedResponse);
+
+ return numbersException.orElseGet(() -> new ApiException(message, code));
+ }
+
+ private static Optional getExceptionFromNumbersOrSmsError(
+ Map, ?> mappedResponse) {
+
+ if (null == mappedResponse) {
+ return Optional.empty();
+ }
+ // excepted numbers API errors have following form
+ // "error": {
+ // "code": int,
+ // "message": string,
+ // "status": string,
+ // }
+
+ if (null == mappedResponse || !mappedResponse.containsKey("error")) {
+ return Optional.empty();
+ }
+ Object error = mappedResponse.get("error");
+ if ((!(error instanceof Map))) {
+ return Optional.empty();
+ }
+
+ Map, ?> errorContent = (Map, ?>) error;
+
+ Integer codeValue = null;
+ if (errorContent.containsKey("code")) {
+ codeValue = Integer.valueOf(String.valueOf(errorContent.get("code")));
+ }
+ String messageValue = String.valueOf(errorContent.get("message"));
+ String statusValue = String.valueOf(errorContent.get("status"));
+
+ if (null == codeValue || null == messageValue || null == statusValue) {
+ return Optional.empty();
+ }
+
+ return Optional.of(
+ new ApiException(String.format("%s: %s", statusValue, messageValue), codeValue));
+ }
+}
diff --git a/core/src/main/com/sinch/sdk/core/exceptions/package-info.java b/core/src/main/com/sinch/sdk/core/exceptions/package-info.java
new file mode 100644
index 00000000..af969153
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/exceptions/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Defined exception related to Sinch API errors
+ *
+ * @since 1.0
+ */
+package com.sinch.sdk.core.exceptions;
diff --git a/core/src/main/com/sinch/sdk/core/http/HttpClient.java b/core/src/main/com/sinch/sdk/core/http/HttpClient.java
new file mode 100644
index 00000000..def19014
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/http/HttpClient.java
@@ -0,0 +1,14 @@
+package com.sinch.sdk.core.http;
+
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.models.ServerConfiguration;
+
+public interface HttpClient extends AutoCloseable {
+
+ boolean isClosed();
+
+ void close() throws Exception;
+
+ HttpResponse invokeAPI(ServerConfiguration serverConfiguration, HttpRequest request)
+ throws ApiException;
+}
diff --git a/core/src/main/com/sinch/sdk/core/http/HttpContentType.java b/core/src/main/com/sinch/sdk/core/http/HttpContentType.java
new file mode 100644
index 00000000..d8f89155
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/http/HttpContentType.java
@@ -0,0 +1,20 @@
+package com.sinch.sdk.core.http;
+
+import java.util.Collection;
+
+public class HttpContentType {
+
+ public static final String CONTENT_TYPE_HEADER = "content-type";
+ public static final String APPLICATION_JSON = "application/json";
+ public static final String TEXT_PLAIN = "text/plain";
+
+ public static boolean isMimeJson(Collection mimes) {
+ String jsonMime = "(?i)^(" + APPLICATION_JSON + "|[^;/ \t]+/[^;/ \t]+[+]json)[ \t]*(;.*)?$";
+ return mimes.stream()
+ .anyMatch(mime -> mime != null && (mime.matches(jsonMime) || mime.equals("*/*")));
+ }
+
+ public static boolean isMimeTextPlain(Collection mimes) {
+ return mimes.stream().anyMatch(TEXT_PLAIN::equalsIgnoreCase);
+ }
+}
diff --git a/core/src/main/com/sinch/sdk/core/http/HttpMapper.java b/core/src/main/com/sinch/sdk/core/http/HttpMapper.java
new file mode 100644
index 00000000..4fa8da25
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/http/HttpMapper.java
@@ -0,0 +1,65 @@
+package com.sinch.sdk.core.http;
+
+import static com.sinch.sdk.core.http.HttpContentType.*;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.sinch.sdk.core.exceptions.ApiException;
+import com.sinch.sdk.core.utils.databind.Mapper;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collection;
+
+public class HttpMapper {
+
+ public T deserialize(HttpResponse response, TypeReference valueType) throws ApiException {
+ if (null == valueType || null == response) {
+ return null;
+ }
+
+ try (InputStream stream = response.getContent()) {
+ if (null == stream) {
+ return null;
+ }
+
+ Collection contentType = response.getHeaders().get(CONTENT_TYPE_HEADER);
+ if (null == contentType || contentType.isEmpty() || isMimeJson(contentType)) {
+ java.util.Scanner s = new java.util.Scanner(stream).useDelimiter("\\A");
+ String content = s.hasNext() ? s.next() : "";
+
+ if ("".equals(content)) {
+ return null;
+ }
+ return Mapper.getInstance().readValue(content, valueType);
+ } else if (isMimeTextPlain(contentType)) {
+ java.util.Scanner s = new java.util.Scanner(stream).useDelimiter("\\A");
+ @SuppressWarnings("unchecked")
+ T t = (T) (s.hasNext() ? s.next() : "");
+ return t;
+ } else {
+ throw new ApiException(
+ "Deserialization for content type '"
+ + contentType
+ + "' not supported for type '"
+ + valueType);
+ }
+ } catch (IOException e) {
+ throw new ApiException(e);
+ }
+ }
+
+ public String serialize(Collection contentTypes, Object body) {
+ if (null == body) {
+ return null;
+ }
+ if (null == contentTypes || contentTypes.isEmpty() || isMimeJson(contentTypes)) {
+ try {
+ return Mapper.getInstance().writeValueAsString(body);
+ } catch (JsonProcessingException e) {
+ throw new ApiException(e);
+ }
+ }
+ throw new ApiException(
+ "Deserialization for content type '" + contentTypes + "' not supported ");
+ }
+}
diff --git a/core/src/main/com/sinch/sdk/core/http/HttpMethod.java b/core/src/main/com/sinch/sdk/core/http/HttpMethod.java
new file mode 100644
index 00000000..f092c090
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/http/HttpMethod.java
@@ -0,0 +1,9 @@
+package com.sinch.sdk.core.http;
+
+public enum HttpMethod {
+ GET,
+ POST,
+ PATCH,
+ PUT,
+ DELETE
+}
diff --git a/core/src/main/com/sinch/sdk/core/http/HttpRequest.java b/core/src/main/com/sinch/sdk/core/http/HttpRequest.java
new file mode 100644
index 00000000..ee072887
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/http/HttpRequest.java
@@ -0,0 +1,68 @@
+package com.sinch.sdk.core.http;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+
+public class HttpRequest {
+
+ private final String path;
+ private final HttpMethod method;
+ private final Collection queryParameters;
+ private final String body;
+ private final Map headerParams;
+ private final Collection accept;
+ private final Collection contentType;
+ private final Collection authNames;
+
+ public HttpRequest(
+ String path,
+ HttpMethod method,
+ Collection queryParameters,
+ String body,
+ Map headerParams,
+ Collection accept,
+ Collection contentType,
+ Collection authNames) {
+ this.path = path;
+ this.method = method;
+ this.queryParameters = queryParameters;
+ this.body = body;
+ this.headerParams = headerParams;
+ this.accept = accept;
+ this.contentType = contentType;
+ this.authNames = authNames;
+ }
+
+ public Optional getPath() {
+ return Optional.ofNullable(path);
+ }
+
+ public HttpMethod getMethod() {
+ return method;
+ }
+
+ public Collection getQueryParameters() {
+ return queryParameters;
+ }
+
+ public String getBody() {
+ return body;
+ }
+
+ public Map getHeaderParams() {
+ return headerParams;
+ }
+
+ public Collection getAccept() {
+ return accept;
+ }
+
+ public Collection getContentType() {
+ return contentType;
+ }
+
+ public Collection getAuthNames() {
+ return authNames;
+ }
+}
diff --git a/core/src/main/com/sinch/sdk/core/http/HttpResponse.java b/core/src/main/com/sinch/sdk/core/http/HttpResponse.java
new file mode 100644
index 00000000..2f97940f
--- /dev/null
+++ b/core/src/main/com/sinch/sdk/core/http/HttpResponse.java
@@ -0,0 +1,61 @@
+package com.sinch.sdk.core.http;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class HttpResponse {
+
+ private final int code;
+
+ private final String message;
+
+ private final Map> headers;
+
+ private final byte[] buffer;
+
+ public HttpResponse(
+ final int code,
+ final String message,
+ final Map> headers,
+ final byte[] buffer) {
+ this.code = code;
+ this.message = null != message ? message : "";
+ this.headers = (null != headers) ? headers : Collections.emptyMap();
+ this.buffer = null != buffer ? buffer : "".getBytes(StandardCharsets.UTF_8);
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public Map