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}