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.sms.messages;
017
018import com.fasterxml.jackson.annotation.JsonValue;
019import com.vonage.client.QueryParamsRequest;
020import java.util.LinkedHashMap;
021import java.util.Map;
022
023/**
024 * Represents the details common to any message that is to be submitted to the Vonage SMS API.
025 */
026public abstract class Message implements QueryParamsRequest {
027    public enum MessageType {
028        /**
029         * Message is a regular TEXT SMS message
030         */
031        TEXT,
032        /**
033         * Message is a binary SMS message with a custom UDH and binary payload
034         */
035        BINARY,
036        /**
037         * Message is a unicode message, for sending messages in non-latin script to a supported handset
038         */
039        UNICODE;
040
041        @Override
042        public String toString() {
043            return super.toString().toLowerCase();
044        }
045    }
046
047    private final MessageType type;
048    private final String from, to;
049    private boolean statusReportRequired;
050    private MessageClass messageClass;
051    private Long timeToLive;
052    private String clientReference, callbackUrl, entityId, contentId;
053
054    protected Message(final MessageType type,
055                      final String from,
056                      final String to) {
057        this(type, from, to, false);
058    }
059
060    /**
061     * Abstract type for more specific SMS message types.<br>
062     * This constructor exposes the full range of possible parameters and is not for general use
063     * Instead, it is accessed via super() in the constructors of various sub-classes that expose a relevant
064     * sub-set of the available parameters
065     *
066     * @param type the type of SMS message to be sent
067     * @param from the 'from' address that will be seen on the handset when this message arrives, typically either a
068     *             valid short-code / long code that can be replied to, or a short text description of the application
069     *             sending the message (Max 15 chars)
070     * @param to   the phone number of the handset you wish to send the message to
071     * @param statusReportRequired flag to enable status updates about the delivery of this message
072     */
073    protected Message(final MessageType type,
074                      final String from,
075                      final String to,
076                      final boolean statusReportRequired) {
077        this.type = type;
078        this.from = from;
079        this.to = to;
080        this.statusReportRequired = statusReportRequired;
081    }
082
083    /**
084     * @return int the type of message will influence the makeup of the request we post to the Vonage server, and also the action taken by the Vonage server in response to this message
085     */
086    public MessageType getType() {
087        return type;
088    }
089
090    /**
091     * @return String the 'from' address that will be seen on the handset when this message arrives,
092     * typically either a valid short-code / long code that can be replied to, or a short text description of the application sending the message (Max 11 chars)
093     */
094    public String getFrom() {
095        return from;
096    }
097
098    /**
099     * @return String the phone number of the handset that you wish to send the message to
100     */
101    public String getTo() {
102        return to;
103    }
104
105    /**
106     * @return String A user definable value that will be stored in the Vonage sms records. It will
107     * be available in detailed reporting and analytics in order to help with reconciliation of messages
108     */
109    public String getClientReference() {
110        return clientReference;
111    }
112
113    public void setClientReference(String clientReference) {
114        if (clientReference.length() > 40) {
115            throw new IllegalArgumentException("Client reference must be 40 characters or less.");
116        }
117        this.clientReference = clientReference;
118    }
119
120    /**
121     * @return {@link MessageClass} The message class that is to be applied to this message.
122     */
123    public MessageClass getMessageClass() {
124        return messageClass;
125    }
126
127    public void setMessageClass(MessageClass messageClass) {
128        this.messageClass = messageClass;
129    }
130
131    public Long getTimeToLive() {
132        return timeToLive;
133    }
134
135    public void setTimeToLive(Long timeToLive) {
136        this.timeToLive = timeToLive;
137    }
138
139    public String getCallbackUrl() {
140        return callbackUrl;
141    }
142
143    public void setCallbackUrl(String callbackUrl) {
144        this.callbackUrl = callbackUrl;
145    }
146
147    public String getEntityId() {
148        return entityId;
149    }
150
151    public void setEntityId(String entityId) {
152        this.entityId = entityId;
153    }
154
155    public String getContentId() {
156        return contentId;
157    }
158
159    public void setContentId(String contentId) {
160        this.contentId = contentId;
161    }
162
163    /**
164     * @return get the value of the 'status-report-req' parameter.
165     */
166    public boolean getStatusReportRequired() {
167        return statusReportRequired;
168    }
169
170    /**
171     * Set the value of the 'status-report-req' parameter.
172     * <p>
173     * If set to 'true', Vonage will call 'callbackUrl' with status updates about the delivery of this message. If this
174     * value is set to 'true', then 'callbackUrl' should also be set to a URL that is configured to receive these
175     * status updates.
176     *
177     * @param statusReportRequired 'true' if status reports are desired, 'false' otherwise.
178     */
179    public void setStatusReportRequired(boolean statusReportRequired) {
180        this.statusReportRequired = statusReportRequired;
181    }
182
183    @Override
184    public Map<String, String> makeParams() {
185        LinkedHashMap<String, String> params = new LinkedHashMap<>();
186        params.put("from", getFrom());
187        params.put("to", getTo());
188        params.put("type", getType().toString());
189        if (getStatusReportRequired()) {
190            params.put("status-report-req", "1");
191        }
192        if (clientReference != null) {
193            params.put("client-ref", getClientReference());
194        }
195        if (timeToLive != null) {
196            params.put("ttl", getTimeToLive().toString());
197        }
198        if (callbackUrl != null) {
199            params.put("callback", getCallbackUrl());
200        }
201        if (messageClass != null) {
202            params.put("message-class", Integer.toString(getMessageClass().getMessageClass()));
203        }
204        if (entityId != null) {
205            params.put("entity-id", getEntityId());
206        }
207        if (contentId != null) {
208            params.put("content-id", getContentId());
209        }
210        return params;
211    }
212
213    /**
214     * An enum of the valid values that may be supplied to as the message-class parameter of a rest submission.
215     */
216    public enum MessageClass {
217        /**
218         * Message Class 0
219         */
220        CLASS_0(0),
221
222        /**
223         * Message Class 1
224         */
225        CLASS_1(1),
226
227        /**
228         * Message Class 2
229         */
230        CLASS_2(2),
231
232        /**
233         * Message Class 3
234         */
235        CLASS_3(3);
236
237        private final int messageClass;
238
239        MessageClass(int messageClass) {
240            this.messageClass = messageClass;
241        }
242
243        @JsonValue
244        public int getMessageClass() {
245            return messageClass;
246        }
247    }
248}