001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/ds/resource/legal-notices/cddl.txt 011 * or http://www.opensource.org/licenses/cddl1.php. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/ds/resource/legal-notices/cddl.txt. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2016-2018 Ping Identity Corporation 026 */ 027package com.unboundid.directory.sdk.ds.api; 028 029import com.unboundid.directory.sdk.broker.internal.BrokerExtension; 030import com.unboundid.directory.sdk.broker.types.BrokerContext; 031import com.unboundid.directory.sdk.common.internal.Configurable; 032import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider; 033import com.unboundid.directory.sdk.common.internal.UnboundIDExtension; 034import com.unboundid.directory.sdk.ds.config.TelephonyMessagingProviderConfig; 035import com.unboundid.ldap.sdk.LDAPException; 036import com.unboundid.util.Extensible; 037import com.unboundid.util.ThreadSafety; 038import com.unboundid.util.ThreadSafetyLevel; 039import com.unboundid.util.args.ArgumentException; 040import com.unboundid.util.args.ArgumentParser; 041 042import java.util.Collections; 043import java.util.List; 044import java.util.Map; 045 046 047 048/** 049 * This class defines an API that may be implemented by extensions that provide 050 * a way to deliver messages to users by telephone, either by SMS or by voice 051 * call. 052 * 053 * <H2>Configuring Telephony Messaging Providers</H2> 054 * <p> 055 * In order to configure a Telephony Messaging Provider created using this 056 * API, use a command like: 057 * </p> 058 * <PRE> 059 * dsconfig create-telephony-messaging-provider \ 060 * ---provider-name "<I>{name}</I>" \ 061 * --type third-party \ 062 * --set "extension-class:<I>{class-name}</I>" \ 063 * --set "extension-argument:<I>{name=value}</I>" 064 * </PRE> 065 * where "<I>{name}</I>" is the name to use for the Telephony Messaging Provider 066 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class 067 * that extends 068 * {@code com.unboundid.directory.sdk.ds.api.TelephonyMessagingProvider}, 069 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to 070 * provide to the Telephony Messaging Provider. If multiple arguments should be 071 * provided to the extension, then the 072 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be 073 * provided multiple times. 074 */ 075@Extensible() 076@BrokerExtension 077@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE) 078public abstract class TelephonyMessagingProvider 079 implements UnboundIDExtension, Configurable, ExampleUsageProvider 080{ 081 /** 082 * Creates a new instance of this Telephony Messaging Provider. All 083 * implementations must include a default constructor, but any 084 * initialization should generally be done in the 085 * {@link #initializeProvider} method. 086 */ 087 public TelephonyMessagingProvider() 088 { 089 // No implementation is required. 090 } 091 092 093 094 /** 095 * {@inheritDoc} 096 */ 097 @Override 098 public abstract String getExtensionName(); 099 100 101 102 /** 103 * {@inheritDoc} 104 */ 105 @Override 106 public abstract String[] getExtensionDescription(); 107 108 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public Map<List<String>,String> getExamplesArgumentSets() 115 { 116 return Collections.emptyMap(); 117 } 118 119 120 121 /** 122 * {@inheritDoc} 123 */ 124 @Override 125 public void defineConfigArguments(final ArgumentParser parser) 126 throws ArgumentException 127 { 128 // No arguments will be allowed by default. 129 } 130 131 132 133 /** 134 * Initializes this Telephony Messaging Provider. Any initialization should be 135 * performed here. This method should generally store the 136 * {@link BrokerContext} in a class member so that it can be used elsewhere 137 * in the implementation. 138 * <p> 139 * The default implementation is empty. 140 * 141 * @param serverContext A handle to the server context for the server in 142 * which this extension is running. Extensions should 143 * typically store this in a class member. 144 * @param config The general configuration for this object. 145 * @param parser The argument parser which has been initialized from 146 * the configuration for this Telephony Messaging 147 * Provider. 148 * @throws Exception If a problem occurs while initializing this store 149 * adapter. 150 */ 151 public void initializeProvider(final BrokerContext serverContext, 152 final TelephonyMessagingProviderConfig config, 153 final ArgumentParser parser) 154 throws Exception 155 { 156 // No initialization will be performed by default. 157 } 158 159 160 161 /** 162 * This hook is called when the Telephony Messaging Provider is disabled or 163 * the server shuts down. Any clean-up of this Telephony Messaging Provider 164 * should be performed here. 165 * <p> 166 * The default implementation is empty. 167 */ 168 public void finalizeProvider() 169 { 170 // No implementation is performed by default. 171 } 172 173 174 175 /** 176 * Indicates whether messages are spoken over a voice call. 177 * @return {@code true} if messages are spoken over a voice call. 178 */ 179 public abstract boolean isMessageSpoken(); 180 181 182 183 /** 184 * Delivers a message to the specified recipient. 185 * 186 * @param recipientNumber The phone number to which the message should 187 * be sent. This must not be {@code null}. 188 * @param message The message to be sent. This must not be 189 * {@code null}. 190 * @param language The language and locale code for the message 191 * (e.g. "en-US"). 192 * 193 * @throws LDAPException If a problem was encountered while sending the 194 * message. 195 */ 196 public abstract void sendMessage(final String recipientNumber, 197 final String message, 198 final String language) 199 throws LDAPException; 200 201 202 203 /** 204 * Delivers a message to the specified recipient, after substituting a 205 * verification code into the message in a form that may be easily understood 206 * by the recipient. The default implementation, which may be overridden if 207 * necessary, inserts a comma and space between each character in the 208 * verification code if the {@code isMessageSpoken} method returns 209 * {@code true}. This should cause the verification code to be spoken slowly, 210 * one character at a time. 211 * 212 * @param recipientNumber The phone number to which the message should 213 * be sent. This must not be {@code null}. 214 * @param message The message to be sent. This must not be 215 * {@code null}. 216 * @param language The language and locale code for the message 217 * (e.g. "en-US"). 218 * @param verificationCodeToken A token to be replaced with a representation 219 * of the provided verification code, wherever 220 * the token appears in the message. 221 * @param verificationCode The verification code to be inserted in 222 * place of the token. 223 * 224 * @throws LDAPException If a problem was encountered while sending the 225 * message. 226 */ 227 public void sendMessage(final String recipientNumber, 228 final String message, 229 final String language, 230 final String verificationCodeToken, 231 final String verificationCode) 232 throws LDAPException 233 { 234 final String messageCode; 235 if (isMessageSpoken()) 236 { 237 // Insert a separator to pause between each character in the code. 238 messageCode = verificationCode.replace("", " ").trim().replace(" ", ", "); 239 } 240 else 241 { 242 messageCode = verificationCode; 243 } 244 245 final String substitutedMessage = 246 message.replace(verificationCodeToken, messageCode); 247 248 sendMessage(recipientNumber, substitutedMessage, language); 249 } 250}