001/*
002 *   Copyright 2024 Vonage
003 *
004 *   Licensed under the Apache License, Version 2.0 (the "License");
005 *   you may not use this file except in compliance with the License.
006 *   You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *   Unless required by applicable law or agreed to in writing, software
011 *   distributed under the License is distributed on an "AS IS" BASIS,
012 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *   See the License for the specific language governing permissions and
014 *   limitations under the License.
015 */
016package com.vonage.client.numbers;
017
018import com.vonage.client.*;
019import com.vonage.client.auth.ApiKeyHeaderAuthMethod;
020import com.vonage.client.common.HttpMethod;
021import java.util.UUID;
022
023/**
024 * A client for accessing the Vonage API calls that manage phone numbers. The standard way to obtain an instance of
025 * this class is to use {@link VonageClient#getNumbersClient()}.
026 */
027public class NumbersClient {
028    final RestEndpoint<ListNumbersFilter, ListNumbersResponse> listNumbers;
029    final RestEndpoint<SearchNumbersFilter, SearchNumbersResponse> searchNumbers;
030    final RestEndpoint<BuyCancelNumberRequest, Void> buyNumber, cancelNumber;
031    final RestEndpoint<UpdateNumberRequest, Void> updateNumber;
032
033    public NumbersClient(HttpWrapper wrapper) {
034        @SuppressWarnings("unchecked")
035        final class Endpoint<T, R> extends DynamicEndpoint<T, R> {
036            Endpoint(final String path, HttpMethod method, R... type) {
037                super(DynamicEndpoint.<T, R> builder(type)
038                        .responseExceptionType(NumbersResponseException.class)
039                        .wrapper(wrapper).requestMethod(method)
040                        .authMethod(ApiKeyHeaderAuthMethod.class)
041                        .urlFormEncodedContentType(method == HttpMethod.POST)
042                        .pathGetter((de, req) -> de.getHttpWrapper().getHttpConfig().getRestBaseUri()+ "/" + path)
043                );
044            }
045        }
046
047        listNumbers = new Endpoint<>("account/numbers", HttpMethod.GET);
048        searchNumbers = new Endpoint<>("number/search", HttpMethod.GET);
049        cancelNumber = new Endpoint<>("number/cancel", HttpMethod.POST);
050        buyNumber = new Endpoint<>("number/buy", HttpMethod.POST);
051        updateNumber = new Endpoint<>("number/update", HttpMethod.POST);
052    }
053
054    /**
055     * Get the first page of phone numbers assigned to the authenticated account.
056     *
057     * @return A ListNumbersResponse containing the first 10 phone numbers
058     *
059     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
060     */
061    public ListNumbersResponse listNumbers() throws NumbersResponseException {
062        return listNumbers(ListNumbersFilter.builder().build());
063    }
064
065    /**
066     * Get a filtered set of numbers assigned to the authenticated account.
067     *
068     * @param filter A ListNumbersFilter describing the filters to be applied to the request.
069     *
070     * @return A ListNumbersResponse containing phone numbers matching the supplied filter.
071     *
072     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
073     */
074    public ListNumbersResponse listNumbers(ListNumbersFilter filter) throws NumbersResponseException {
075        return listNumbers.execute(filter);
076    }
077
078    /**
079     * Search for available Vonage Virtual Numbers.
080     *
081     * @param country Country to search available numbers from.
082     *
083     * @return Available Vonage Virtual Numbers.
084     *
085     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
086     */
087    public SearchNumbersResponse searchNumbers(String country) throws NumbersResponseException {
088        return searchNumbers(SearchNumbersFilter.builder().country(country).build());
089    }
090
091    /**
092     * Search for available Vonage Virtual Numbers.
093     *
094     * @param filter search for available Vonage Virtual Number with filters
095     * @return The available Vonage Virtual Numbers.
096     *
097     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
098     */
099    public SearchNumbersResponse searchNumbers(SearchNumbersFilter filter) throws NumbersResponseException {
100        return searchNumbers.execute(filter);
101    }
102
103    /**
104     * Start renting a Vonage Virtual Number.
105     *
106     * @param country The two character country code in ISO 3166-1 alpha-2 format.
107     * @param msisdn  The phone number to be bought in E.164 format.
108     *
109     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
110     */
111    public void buyNumber(String country, String msisdn) throws NumbersResponseException {
112        buyNumber(country, msisdn, null);
113    }
114
115    /**
116     * Start renting a Vonage Virtual Number.
117     *
118     * @param country      The two character country code in ISO 3166-1 alpha-2 format.
119     * @param msisdn       The phone number to be bought in E.164 format.
120     * @param targetApiKey If you’d like to perform an action on a subaccount, provide the API key of that
121     *                     account here. If you’d like to perform an action on your own account,
122     *                     you do not need to provide this field.
123     *
124     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
125     * @see #buyNumber(String, String)
126     * @since 8.10.0
127     */
128    public void buyNumber(String country, String msisdn, String targetApiKey) throws NumbersResponseException {
129        buyNumber.execute(new BuyCancelNumberRequest(country, msisdn, targetApiKey));
130    }
131
132    /**
133     * Stop renting a Vonage Virtual Number.
134     *
135     * @param country The two character country code in ISO 3166-1 alpha-2 format.
136     * @param msisdn  The phone number to be cancelled in E.164 format.
137     *
138     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
139     */
140    public void cancelNumber(String country, String msisdn) throws NumbersResponseException {
141        cancelNumber(country, msisdn, null);
142    }
143
144    /**
145     * Stop renting a Vonage Virtual Number.
146     *
147     * @param country      The two character country code in ISO 3166-1 alpha-2 format.
148     * @param msisdn       The phone number to be cancelled in E.164 format.
149     * @param targetApiKey If you’d like to perform an action on a subaccount, provide the API key of that
150     *                     account here. If you’d like to perform an action on your own account,
151     *                     you do not need to provide this field.
152     *
153     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
154     * @see #cancelNumber(String, String)
155     * @since 8.10.0
156     */
157    public void cancelNumber(String country, String msisdn, String targetApiKey) throws NumbersResponseException {
158        cancelNumber.execute(new BuyCancelNumberRequest(country, msisdn, targetApiKey));
159    }
160
161    /**
162     * Update the callbacks and/or application associations for a given Vonage Virtual Number.
163     *
164     * @param request Details of the updates to be made to the number association.
165     *
166     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
167     */
168    public void updateNumber(UpdateNumberRequest request) throws NumbersResponseException {
169        updateNumber.execute(request);
170    }
171
172    /**
173     * Link a given Vonage Virtual Number to a Vonage Application with the given ID.
174     *
175     * @param msisdn  The Vonage Virtual Number to be updated.
176     * @param country The country for the given msisdn.
177     * @param appId   The UUID for the Vonage Application to be associated with the number.
178     *
179     * @throws NumbersResponseException If the API call returned an unsuccessful (4xx or 5xx) response.
180     */
181    public void linkNumber(String msisdn, String country, String appId) throws NumbersResponseException {
182        updateNumber(UpdateNumberRequest.builder(msisdn, country)
183                .voiceCallback(UpdateNumberRequest.CallbackType.APP, UUID.fromString(appId).toString()).build());
184    }
185}