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.voice.ncco; 017 018import com.fasterxml.jackson.annotation.JsonProperty; 019import com.vonage.client.JsonableBaseObject; 020import com.vonage.client.voice.AdvancedMachineDetection; 021import com.vonage.client.voice.MachineDetection; 022import java.net.URI; 023import java.util.Arrays; 024import java.util.Collection; 025 026/** 027 * An NCCO connect action that allows for the establishment of a connection to various {@link Endpoint}. 028 */ 029public class ConnectAction extends JsonableBaseObject implements Action { 030 private static final String ACTION = "connect"; 031 032 private Collection<Endpoint> endpoint; 033 private String from; 034 private EventType eventType; 035 private Integer limit, timeOut; 036 private MachineDetection machineDetection; 037 private AdvancedMachineDetection advancedMachineDetection; 038 private Collection<String> eventUrl; 039 private EventMethod eventMethod; 040 private Boolean randomFromNumber; 041 private URI ringbackTone; 042 043 ConnectAction() {} 044 045 private ConnectAction(Builder builder) { 046 if ((endpoint = builder.endpoint) == null || endpoint.isEmpty()) { 047 throw new IllegalStateException("An endpoint must be specified."); 048 } 049 if ((limit = builder.limit) != null && (limit < 1 || limit > 7200)) { 050 throw new IllegalArgumentException("'limit' must be positive and less than 7200 seconds."); 051 } 052 if ((timeOut = builder.timeOut) != null && (timeOut < 3 || timeOut > 7200)) { 053 throw new IllegalArgumentException("'timeOut' must be between 3 and 7200 seconds."); 054 } 055 from = builder.from; 056 if ((randomFromNumber = builder.randomFromNumber) != null && from != null) { 057 throw new IllegalStateException("'randomFromNumber' and 'from' cannot be used together."); 058 } 059 eventType = builder.eventType; 060 machineDetection = builder.machineDetection; 061 advancedMachineDetection = builder.advancedMachineDetection; 062 eventUrl = builder.eventUrl; 063 eventMethod = builder.eventMethod; 064 ringbackTone = builder.ringbackTone; 065 } 066 067 @JsonProperty("action") 068 @Override 069 public String getAction() { 070 return ACTION; 071 } 072 073 @JsonProperty("endpoint") 074 public Collection<Endpoint> getEndpoint() { 075 return endpoint; 076 } 077 078 @JsonProperty("from") 079 public String getFrom() { 080 return from; 081 } 082 083 @JsonProperty("eventType") 084 public EventType getEventType() { 085 return eventType; 086 } 087 088 @JsonProperty("timeout") 089 public Integer getTimeOut() { 090 return timeOut; 091 } 092 093 @JsonProperty("limit") 094 public Integer getLimit() { 095 return limit; 096 } 097 098 @JsonProperty("machineDetection") 099 public MachineDetection getMachineDetection() { 100 return machineDetection; 101 } 102 103 @JsonProperty("advancedMachineDetection") 104 public AdvancedMachineDetection getAdvancedMachineDetection() { 105 return advancedMachineDetection; 106 } 107 108 @JsonProperty("eventUrl") 109 public Collection<String> getEventUrl() { 110 return eventUrl; 111 } 112 113 @JsonProperty("eventMethod") 114 public EventMethod getEventMethod() { 115 return eventMethod; 116 } 117 118 @JsonProperty("randomFromNumber") 119 public Boolean getRandomFromNumber() { 120 return randomFromNumber; 121 } 122 123 @JsonProperty("ringbackTone") 124 public URI getRingbackTone() { 125 return ringbackTone; 126 } 127 128 /** 129 * Entry point for constructing an instance of this class. 130 * 131 * @param endpoint Connect the call to a specific #{@link Endpoint}. 132 * 133 * @return A new Builder. 134 */ 135 public static Builder builder(Collection<Endpoint> endpoint) { 136 return new Builder(endpoint); 137 } 138 139 /** 140 * Entry point for constructing an instance of this class. 141 * 142 * @param endpoint Connect the call to a specific {@linkplain Endpoint}. 143 * 144 * @return A new Builder. 145 */ 146 public static Builder builder(Endpoint... endpoint) { 147 return builder(Arrays.asList(endpoint)); 148 } 149 150 public static class Builder { 151 private Collection<Endpoint> endpoint; 152 private String from; 153 private EventType eventType; 154 private Integer timeOut, limit; 155 private MachineDetection machineDetection; 156 private AdvancedMachineDetection advancedMachineDetection; 157 private Collection<String> eventUrl; 158 private EventMethod eventMethod; 159 private Boolean randomFromNumber; 160 private URI ringbackTone; 161 162 Builder(Collection<Endpoint> endpoint) { 163 this.endpoint = endpoint; 164 } 165 166 /** 167 * Connect the call to a specific {@linkplain Endpoint}. 168 * 169 * @param endpoint The endpoints to connect to. 170 * 171 * @return This builder. 172 * @deprecated This will be removed in the next major release. 173 */ 174 @Deprecated 175 public Builder endpoint(Collection<Endpoint> endpoint) { 176 this.endpoint = endpoint; 177 return this; 178 } 179 180 /** 181 * Connect the call to a specific {@linkplain Endpoint}. 182 * 183 * @param endpoint The endpoint(s) to connect to. 184 * 185 * @return This builder. 186 */ 187 public Builder endpoint(Endpoint... endpoint) { 188 return endpoint(Arrays.asList(endpoint)); 189 } 190 191 /** 192 * Sets the caller ID number. This must be one of your Vonage virtual numbers. 193 * Any other value will result in the caller ID being unknown. 194 * 195 * @param from The caller number in <a href="https://en.wikipedia.org/wiki/E.164">E.164 format</a>. 196 * 197 * @return This builder. 198 */ 199 public Builder from(String from) { 200 this.from = from; 201 return this; 202 } 203 204 /** 205 * Set to {@link EventType#SYNCHRONOUS} to: 206 * <ul> 207 * <li>Make the connect action synchronous. 208 * <li>Enable eventUrl to return an NCCO that overrides the current NCCO when a call moves to 209 * specific states. 210 * </ul> 211 * <p> 212 * See the <a href="https://developer.vonage.com/voice/voice-api/ncco-reference#connect-with-fallback-ncco">Connect with fallback NCCO example.</a> 213 * 214 * @param eventType The event type as an enum. 215 * 216 * @return This builder. 217 */ 218 public Builder eventType(EventType eventType) { 219 this.eventType = eventType; 220 return this; 221 } 222 223 /** 224 * If the call is unanswered, set the number in seconds before Vonage stops ringing endpoint. 225 * The default value is 60, minimum is 3 and maximum is 7200 (2 hours). 226 * 227 * @param timeOut The call timeout in seconds. 228 * 229 * @return This builder. 230 */ 231 public Builder timeOut(Integer timeOut) { 232 this.timeOut = timeOut; 233 return this; 234 } 235 236 /** 237 * Maximum length of the call in seconds. The default and maximum value is 7200 seconds (2 hours). 238 * 239 * @param limit The maximum call length as an int. 240 * 241 * @return This builder. 242 */ 243 public Builder limit(Integer limit) { 244 this.limit = limit; 245 return this; 246 } 247 248 /** 249 * Configure the behavior when Vonage detects that a destination is an answerphone. 250 * 251 * @param machineDetection 252 * Set to either: 253 * <ul> 254 * <li> {@link MachineDetection#CONTINUE} Vonage sends an HTTP request to event_url with the Call event machine 255 * <li> {@link MachineDetection#HANGUP} to end the Call 256 * </ul> 257 * 258 * @return This builder. 259 */ 260 public Builder machineDetection(MachineDetection machineDetection) { 261 this.machineDetection = machineDetection; 262 return this; 263 } 264 265 /** 266 * Configure the behavior of Vonage's advanced machine detection. This overrides the 267 * {@link #machineDetection(MachineDetection)}, so you cannot set both. 268 * 269 * @param advancedMachineDetection The advanced machine detection settings. 270 * 271 * @return This builder. 272 * 273 * @since 7.4.0 274 */ 275 public Builder advancedMachineDetection(AdvancedMachineDetection advancedMachineDetection) { 276 this.advancedMachineDetection = advancedMachineDetection; 277 return this; 278 } 279 280 /** 281 * Set the webhook endpoint that Vonage calls asynchronously on each of the possible 282 * <a href="https://developer.nexmo.com/voice/voice-api/guides/call-flow#call-states">Call States</a>. 283 * If eventType is set to synchronous the eventUrl can return an NCCO that overrides the current 284 * NCCO when a timeout occurs. 285 * 286 * @param eventUrl The event URLs. 287 * 288 * @return This builder. 289 */ 290 public Builder eventUrl(Collection<String> eventUrl) { 291 this.eventUrl = eventUrl; 292 return this; 293 } 294 295 /** 296 * Set the webhook endpoint that Vonage calls asynchronously on each of the possible 297 * <a href="https://developer.nexmo.com/voice/voice-api/guides/call-flow#call-states">Call States</a>. 298 * If eventType is set to synchronous the eventUrl can return an NCCO that overrides the current 299 * NCCO when a timeout occurs. 300 * 301 * @param eventUrl The event URL(s). 302 * 303 * @return This builder. 304 */ 305 public Builder eventUrl(String... eventUrl) { 306 return eventUrl(Arrays.asList(eventUrl)); 307 } 308 309 /** 310 * The HTTP method Vonage uses to make the request to eventUrl. 311 * The default value is {@linkplain EventMethod#POST}. 312 * 313 * @param eventMethod The HTTP method as an enum. 314 * 315 * @return This builder. 316 */ 317 public Builder eventMethod(EventMethod eventMethod) { 318 this.eventMethod = eventMethod; 319 return this; 320 } 321 322 /** 323 * Use a random phone number as {@code from}. The number will be selected from the list of the 324 * numbers assigned to the current application. The application will try to use number(s) from the 325 * same country as the destination (if available). If set to {@code true}, cannot be used together 326 * with {@linkplain #from(String)}. The default value is {@code false}. 327 * 328 * @param randomFromNumber {@code true} to use a random number instead of {@linkplain #from(String)}. 329 * 330 * @return This builder. 331 * @since 8.2.0 332 */ 333 public Builder randomFromNumber(boolean randomFromNumber) { 334 this.randomFromNumber = randomFromNumber; 335 return this; 336 } 337 338 /** 339 * A URL value that points to a ringback tone to be played back on repeat to the caller, so they don't 340 * hear silence. The tone will automatically stop playing when the call is fully connected. It's not 341 * recommended to use this parameter when connecting to a phone endpoint, as the carrier will supply 342 * their own ringback tone. 343 * 344 * @param ringbackTone The ringback tone URL as a string. 345 * 346 * @return This builder. 347 * @since 8.2.0 348 */ 349 public Builder ringbackTone(String ringbackTone) { 350 this.ringbackTone = URI.create(ringbackTone); 351 return this; 352 } 353 354 /** 355 * Builds the ConnectAction. 356 * 357 * @return A new {@link ConnectAction} object from the stored builder options. 358 */ 359 public ConnectAction build() { 360 return new ConnectAction(this); 361 } 362 } 363}