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.proactiveconnect; 017 018import com.vonage.client.*; 019import com.vonage.client.auth.JWTAuthMethod; 020import com.vonage.client.common.HalPageResponse; 021import com.vonage.client.common.HttpMethod; 022import java.io.IOException; 023import java.nio.file.Files; 024import java.nio.file.Path; 025import java.util.List; 026import java.util.Map; 027import java.util.Objects; 028import java.util.UUID; 029import java.util.function.Function; 030 031/** 032 * A client for talking to the Vonage Proactive Connect API. The standard way to obtain an instance 033 * of this class is to use {@link VonageClient#getProactiveConnectClient()}. 034 * 035 * @deprecated This API is sunset and will be removed in the next major release. 036 */ 037@Deprecated 038public class ProactiveConnectClient { 039 final RestEndpoint<ContactsList, ContactsList> createList, updateList; 040 final RestEndpoint<UUID, ContactsList> getList; 041 final RestEndpoint<UUID, Void> deleteList, clearList, fetchList; 042 final RestEndpoint<HalRequestWrapper, ListListsResponse> listLists; 043 final RestEndpoint<HalRequestWrapper, ListItemsResponse> listItems; 044 final RestEndpoint<ListItemRequestWrapper, ListItem> createListItem, getListItem, updateListItem; 045 final RestEndpoint<ListItemRequestWrapper, Void> deleteListItem; 046 final RestEndpoint<UUID, byte[]> downloadListItems; 047 final RestEndpoint<UploadListItemsRequestWrapper, UploadListItemsResponse> uploadListItems; 048 final RestEndpoint<ListEventsFilter, ListEventsResponse> listEvents; 049 050 /** 051 * Constructor. 052 * 053 * @param wrapper (REQUIRED) shared HTTP wrapper object used for making REST calls. 054 */ 055 public ProactiveConnectClient(HttpWrapper wrapper) { 056 057 @SuppressWarnings("unchecked") 058 class Endpoint<T, R> extends DynamicEndpoint<T, R> { 059 Endpoint(Function<T, String> pathGetter, HttpMethod method, R... type) { 060 super(DynamicEndpoint.<T, R> builder(type).authMethod(JWTAuthMethod.class) 061 .responseExceptionType(ProactiveConnectResponseException.class) 062 .requestMethod(method).wrapper(wrapper).pathGetter((de, req) -> { 063 String base = de.getHttpWrapper().getHttpConfig().getApiEuBaseUri(); 064 return base + "/v0.1/bulk/" + pathGetter.apply(req); 065 }) 066 ); 067 } 068 } 069 070 createList = new Endpoint<>(req -> "lists", HttpMethod.POST); 071 getList = new Endpoint<>(listId -> "lists/"+listId, HttpMethod.GET); 072 updateList = new Endpoint<>(list -> "lists/"+list.getId(), HttpMethod.PUT); 073 deleteList = new Endpoint<>(listId -> "lists/"+listId, HttpMethod.DELETE); 074 clearList = new Endpoint<>(listId -> "lists/"+listId+"/clear", HttpMethod.POST); 075 fetchList = new Endpoint<>(listId -> "lists/"+listId+"/fetch", HttpMethod.POST); 076 listLists = new Endpoint<>(req -> "lists", HttpMethod.GET); 077 listItems = new Endpoint<>(req -> "lists/"+req.id+"/items", HttpMethod.GET); 078 createListItem = new Endpoint<>(req -> "lists/"+req.listId+"/items", HttpMethod.POST); 079 getListItem = new Endpoint<>(req -> "lists/"+req.listId+"/items/"+req.itemId, HttpMethod.GET); 080 updateListItem = new Endpoint<>(req -> "lists/"+req.listId+"/items/"+req.itemId, HttpMethod.PUT); 081 deleteListItem = new Endpoint<>(req -> "lists/"+req.listId+"/items/"+req.itemId, HttpMethod.DELETE); 082 downloadListItems = new Endpoint<>(listId -> "lists/"+listId+"/items/download", HttpMethod.GET); 083 uploadListItems = new Endpoint<>(req -> "lists/"+req.listId+"/items/import", HttpMethod.POST); 084 listEvents = new Endpoint<>(req -> "events", HttpMethod.GET); 085 } 086 087 private UUID validateUuid(String name, UUID uuid) { 088 return Objects.requireNonNull(uuid, name+" is required."); 089 } 090 091 private <R extends HalPageResponse> R halRequest(RestEndpoint<HalRequestWrapper, R> endpoint, 092 String id, Integer page, Integer pageSize, SortOrder order) { 093 if (page != null && page < 1) { 094 throw new IllegalArgumentException("Page number must be positive."); 095 } 096 if (pageSize != null && pageSize < 1) { 097 throw new IllegalArgumentException("Page size must be positive."); 098 } 099 return endpoint.execute(new HalRequestWrapper(page, pageSize, order != null ? order.toSortOrder() : null, id)); 100 } 101 102 /** 103 * Create a new list. 104 * 105 * @param list The new list's properties. 106 * 107 * @return The list that was created with updated metadata. 108 * 109 * @throws ProactiveConnectResponseException If the request was unsuccessful. 110 * This could be for the following reasons: 111 * <ul> 112 * <li><b>400</b>: Invalid request parameter or body.</li> 113 * <li><b>409</b>: Conflict.</li> 114 * <li><b>422</b>: Resource limit reached / exceeded.</li> 115 * </ul> 116 */ 117 public ContactsList createList(ContactsList list) { 118 return createList.execute(Objects.requireNonNull(list, "List structure is required.")); 119 } 120 121 /** 122 * Retrieve a list. 123 * 124 * @param listId Unique ID of the list. 125 * 126 * @return The list associated with the ID. 127 * 128 * @throws ProactiveConnectResponseException If the list does not exist or couldn't be retrieved. 129 */ 130 public ContactsList getList(UUID listId) { 131 return getList.execute(validateUuid("List ID", listId)); 132 } 133 134 /** 135 * Update an existing list. 136 * 137 * @param listId Unique ID of the list. 138 * @param updatedList The new list properties. 139 * 140 * @return The updated list. 141 * 142 * @throws ProactiveConnectResponseException If the request was unsuccessful. 143 * This could be for the following reasons: 144 * <ul> 145 * <li><b>400</b>: Invalid request parameter or body.</li> 146 * <li><b>404</b>: List not found.</li> 147 * <li><b>409</b>: Conflict.</li> 148 * </ul> 149 */ 150 public ContactsList updateList(UUID listId, ContactsList updatedList) { 151 Objects.requireNonNull(updatedList, "List structure is required."); 152 updatedList.id = validateUuid("List ID", listId); 153 return updateList.execute(updatedList); 154 } 155 156 /** 157 * Delete a list. 158 * 159 * @param listId Unique ID of the list. 160 * 161 * @throws ProactiveConnectResponseException If the list does not exist or couldn't be deleted. 162 */ 163 public void deleteList(UUID listId) { 164 deleteList.execute(validateUuid("List ID", listId)); 165 } 166 167 /** 168 * Delete all items in a list. 169 * 170 * @param listId Unique ID of the list. 171 * 172 * @throws ProactiveConnectResponseException If the list does not exist or couldn't be cleared. 173 */ 174 public void clearList(UUID listId) { 175 clearList.execute(validateUuid("List ID", listId)); 176 } 177 178 /** 179 * Fetch and replace all items from datasource. 180 * 181 * @param listId Unique ID of the list. 182 * 183 * @throws ProactiveConnectResponseException If the list does not exist or couldn't be fetched. 184 */ 185 public void fetchList(UUID listId) { 186 fetchList.execute(validateUuid("List ID", listId)); 187 } 188 189 /** 190 * Gets the first 1000 lists in the application. 191 * 192 * @return The lists in order of creation. 193 * 194 * @throws ProactiveConnectResponseException If there was an error in retrieving the lists. 195 */ 196 public List<ContactsList> listLists() { 197 return halRequest(listLists, null, 1, 1000, null).getLists(); 198 } 199 200 /** 201 * Get all lists on a particular page. 202 * 203 * @param page The page number of the HAL response to parse results. 204 * @param pageSize Number of results per page in the HAL response. 205 * @param order The order to sort results by (ascending or descending). 206 * 207 * @return The lists page. 208 * 209 * @throws ProactiveConnectResponseException If there was an error in retrieving the lists. 210 */ 211 public ListListsResponse listLists(int page, int pageSize, SortOrder order) { 212 return halRequest(listLists, null, page, pageSize, order); 213 } 214 215 /** 216 * Create a new list item. 217 * 218 * @param listId Unique ID of the list. 219 * @param data The new item's data as a Map. 220 * 221 * @return The created list item. 222 * 223 * @throws ProactiveConnectResponseException If the request was unsuccessful. 224 * This could be for the following reasons: 225 * <ul> 226 * <li><b>400</b>: Invalid request parameter or body.</li> 227 * <li><b>404</b>: List not found.</li> 228 * <li><b>422</b>: Resource limit reached / exceeded.</li> 229 * </ul> 230 */ 231 public ListItem createListItem(UUID listId, Map<String, ?> data) { 232 return createListItem.execute(new ListItemRequestWrapper( 233 validateUuid("List ID", listId), null, 234 Objects.requireNonNull(data, "List data is required.") 235 )); 236 } 237 238 /** 239 * Retrieve a list item. 240 * 241 * @param listId Unique ID of the list. 242 * @param itemId Unique ID of the item. 243 * 244 * @return The requested list item. 245 * 246 * @throws ProactiveConnectResponseException If the list or item does not exist or couldn't be retrieved. 247 */ 248 public ListItem getListItem(UUID listId, UUID itemId) { 249 return getListItem.execute(new ListItemRequestWrapper( 250 validateUuid("List ID", listId), validateUuid("Item ID", itemId), null 251 )); 252 } 253 254 /** 255 * Update an existing list item. 256 * 257 * @param listId Unique ID of the list. 258 * @param itemId Unique ID of the item. 259 * @param data The updated item data as a Map. 260 * 261 * @return The updated list item. 262 * 263 * @throws ProactiveConnectResponseException If the request was unsuccessful. 264 * This could be for the following reasons: 265 * <ul> 266 * <li><b>400</b>: Invalid request parameter or body.</li> 267 * <li><b>404</b>: List or item not found.</li> 268 * </ul> 269 */ 270 public ListItem updateListItem(UUID listId, UUID itemId, Map<String, ?> data) { 271 return updateListItem.execute(new ListItemRequestWrapper( 272 validateUuid("List ID", listId), 273 validateUuid("Item ID", itemId), 274 Objects.requireNonNull(data, "List item data is required.") 275 )); 276 } 277 278 /** 279 * Delete a list item. 280 * 281 * @param listId Unique ID of the list. 282 * @param itemId Unique ID of the item. 283 * 284 * @throws ProactiveConnectResponseException If the list or item does not exist or couldn't be deleted. 285 */ 286 public void deleteListItem(UUID listId, UUID itemId) { 287 deleteListItem.execute(new ListItemRequestWrapper( 288 validateUuid("List ID", listId), validateUuid("Item ID", itemId), null 289 )); 290 } 291 292 /** 293 * Download all items in a list in CSV format. 294 * Use {@link #downloadListItems(UUID, Path)} to save the CSV as a file. 295 * 296 * @param listId Unique ID of the list. 297 * 298 * @return The list items contents as a CSV-formatted String. 299 * @see #downloadListItems(UUID, Path) 300 * 301 * @throws ProactiveConnectResponseException If the list does not exist or couldn't be retrieved. 302 */ 303 public String downloadListItems(UUID listId) { 304 return new String(downloadListItems.execute(validateUuid("List ID", listId))); 305 } 306 307 /** 308 * Download all items in a list in CSV format. 309 * Use {@link #downloadListItems(UUID)} to get the results as a String. 310 * 311 * @param listId Unique ID of the list. 312 * @param file Path of the file to write the downloaded results to. 313 * 314 * @throws ProactiveConnectResponseException If the list does not exist or couldn't be retrieved. 315 */ 316 public void downloadListItems(UUID listId, Path file) { 317 try { 318 Files.write( 319 Objects.requireNonNull(file, "CSV file is required."), 320 downloadListItems.execute(validateUuid("List ID", listId)) 321 ); 322 } 323 catch (IOException ex) { 324 throw new VonageUnexpectedException("Couldn't write list '"+listId+"' to file '"+file+"'", ex); 325 } 326 } 327 328 /** 329 * Import list items from a CSV file. 330 * 331 * @param listId Unique ID of the list. 332 * @param csvFile Path to the CSV file to upload. 333 * 334 * @return Result of the upload if successful. 335 * 336 * @throws ProactiveConnectResponseException If the request was unsuccessful. 337 * This could be for the following reasons: 338 * <ul> 339 * <li><b>404</b>: List not found.</li> 340 * <li><b>422</b>: Resource limit reached / exceeded.</li> 341 * </ul> 342 */ 343 public UploadListItemsResponse uploadListItems(UUID listId, Path csvFile) { 344 try { 345 byte[] data = Files.readAllBytes(csvFile); 346 return uploadListItems.execute(new UploadListItemsRequestWrapper( 347 validateUuid("List ID", listId), data 348 )); 349 } 350 catch (IOException ex) { 351 throw new VonageClientException("Could not read from file.", ex); 352 } 353 } 354 355 /** 356 * Gets the first 1000 events in the application. 357 * 358 * @param listId Unique ID of the list to retrieve items from. 359 * 360 * @return The events in order of creation. 361 * 362 * @throws ProactiveConnectResponseException If the list does not exist or the items couldn't be retrieved. 363 */ 364 public List<ListItem> listItems(UUID listId) { 365 return halRequest(listItems, 366 validateUuid("List ID", listId).toString(), 367 1, 1000, null 368 ).getItems(); 369 } 370 371 /** 372 * Get all items on a particular page. 373 * 374 * @param listId Unique ID of the list to retrieve items from. 375 * @param page The page number of the HAL response to parse results. 376 * @param pageSize Number of results per page in the HAL response. 377 * @param order The order to sort results by (ascending or descending). 378 * 379 * @return The items page. 380 * 381 * @throws ProactiveConnectResponseException If the list does not exist or the items couldn't be retrieved. 382 */ 383 public ListItemsResponse listItems(UUID listId, int page, int pageSize, SortOrder order) { 384 return halRequest(listItems, validateUuid("List ID", listId).toString(), page, pageSize, order); 385 } 386 387 /** 388 * Gets all events in the application matching the criteria. 389 * 390 * @param filter Optional attributes to narrow down the results. 391 * 392 * @return The list of events applicable to the request criteria, in order of creation. 393 * 394 * @throws ProactiveConnectResponseException If the events couldn't be retrieved. 395 */ 396 public List<Event> listEvents(ListEventsFilter filter) { 397 return listEvents.execute(filter != null ? filter : ListEventsFilter.builder().build()).getEvents(); 398 } 399}