]> git.basschouten.com Git - openhab-addons.git/blob
878b12ab9704981c7659375241e241725cf909a6
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.pushover.internal.connection;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.util.Arrays;
18 import java.util.List;
19 import java.util.stream.Collectors;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.eclipse.jetty.client.api.ContentProvider;
24 import org.eclipse.jetty.client.util.MultiPartContentProvider;
25 import org.eclipse.jetty.client.util.PathContentProvider;
26 import org.eclipse.jetty.client.util.StringContentProvider;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * The {@link PushoverMessageBuilder} builds the body for Pushover Messages API requests.
32  *
33  * @author Christoph Weitkamp - Initial contribution
34  */
35 @NonNullByDefault
36 public class PushoverMessageBuilder {
37
38     private final Logger logger = LoggerFactory.getLogger(PushoverMessageBuilder.class);
39
40     public static final String MESSAGE_KEY_TOKEN = "token";
41     private static final String MESSAGE_KEY_USER = "user";
42     private static final String MESSAGE_KEY_MESSAGE = "message";
43     private static final String MESSAGE_KEY_TITLE = "title";
44     private static final String MESSAGE_KEY_DEVICE = "device";
45     private static final String MESSAGE_KEY_PRIORITY = "priority";
46     private static final String MESSAGE_KEY_RETRY = "retry";
47     private static final String MESSAGE_KEY_EXPIRE = "expire";
48     private static final String MESSAGE_KEY_URL = "url";
49     private static final String MESSAGE_KEY_URL_TITLE = "url_title";
50     private static final String MESSAGE_KEY_SOUND = "sound";
51     private static final String MESSAGE_KEY_ATTACHMENT = "attachment";
52     public static final String MESSAGE_KEY_HTML = "html";
53     public static final String MESSAGE_KEY_MONOSPACE = "monospace";
54
55     private static final int MAX_MESSAGE_LENGTH = 1024;
56     private static final int MAX_TITLE_LENGTH = 250;
57     private static final int MAX_DEVICE_LENGTH = 25;
58     private static final List<Integer> VALID_PRIORITY_LIST = Arrays.asList(-2, -1, 0, 1, 2);
59     private static final int DEFAULT_PRIORITY = 0;
60     public static final int EMERGENCY_PRIORITY = 2;
61     private static final int MIN_RETRY_SECONDS = 30;
62     private static final int MAX_EXPIRE_SECONDS = 10800;
63     private static final int MAX_URL_LENGTH = 512;
64     private static final int MAX_URL_TITLE_LENGTH = 100;
65     public static final String DEFAULT_CONTENT_TYPE = "image/jpeg";
66
67     private final MultiPartContentProvider body = new MultiPartContentProvider();
68
69     private @Nullable String message;
70     private @Nullable String title;
71     private @Nullable String device;
72     private int priority = DEFAULT_PRIORITY;
73     private int retry = 300;
74     private int expire = 3600;
75     private @Nullable String url;
76     private @Nullable String urlTitle;
77     private @Nullable String sound;
78     private @Nullable String attachment;
79     private String contentType = DEFAULT_CONTENT_TYPE;
80     private boolean html = false;
81     private boolean monospace = false;
82
83     private PushoverMessageBuilder(String apikey, String user) throws PushoverConfigurationException {
84         body.addFieldPart(MESSAGE_KEY_TOKEN, new StringContentProvider(apikey), null);
85         body.addFieldPart(MESSAGE_KEY_USER, new StringContentProvider(user), null);
86     }
87
88     public static PushoverMessageBuilder getInstance(@Nullable String apikey, @Nullable String user)
89             throws PushoverConfigurationException {
90         if (apikey == null || apikey.isEmpty()) {
91             throw new PushoverConfigurationException("@text/offline.conf-error-missing-apikey");
92         }
93
94         if (user == null || user.isEmpty()) {
95             throw new PushoverConfigurationException("@text/offline.conf-error-missing-user");
96         }
97
98         return new PushoverMessageBuilder(apikey, user);
99     }
100
101     public PushoverMessageBuilder withMessage(String message) {
102         this.message = message;
103         return this;
104     }
105
106     public PushoverMessageBuilder withTitle(String title) {
107         this.title = title;
108         return this;
109     }
110
111     public PushoverMessageBuilder withDevice(String device) {
112         this.device = device;
113         return this;
114     }
115
116     public PushoverMessageBuilder withPriority(int priority) {
117         this.priority = priority;
118         return this;
119     }
120
121     public PushoverMessageBuilder withRetry(int retry) {
122         this.retry = retry;
123         return this;
124     }
125
126     public PushoverMessageBuilder withExpire(int expire) {
127         this.expire = expire;
128         return this;
129     }
130
131     public PushoverMessageBuilder withUrl(String url) {
132         this.url = url;
133         return this;
134     }
135
136     public PushoverMessageBuilder withUrlTitle(String urlTitle) {
137         this.urlTitle = urlTitle;
138         return this;
139     }
140
141     public PushoverMessageBuilder withSound(String sound) {
142         this.sound = sound;
143         return this;
144     }
145
146     public PushoverMessageBuilder withAttachment(String attachment) {
147         this.attachment = attachment;
148         return this;
149     }
150
151     public PushoverMessageBuilder withContentType(String contentType) {
152         this.contentType = contentType;
153         return this;
154     }
155
156     public PushoverMessageBuilder withHtmlFormatting() {
157         this.html = true;
158         return this;
159     }
160
161     public PushoverMessageBuilder withMonospaceFormatting() {
162         this.monospace = true;
163         return this;
164     }
165
166     public ContentProvider build() {
167         if (message != null) {
168             if (message.length() > MAX_MESSAGE_LENGTH) {
169                 throw new IllegalArgumentException(String.format(
170                         "Skip sending the message as 'message' is longer than %d characters.", MAX_MESSAGE_LENGTH));
171             }
172             body.addFieldPart(MESSAGE_KEY_MESSAGE, new StringContentProvider(message), null);
173         }
174
175         if (title != null) {
176             if (title.length() > MAX_TITLE_LENGTH) {
177                 throw new IllegalArgumentException(String
178                         .format("Skip sending the message as 'title' is longer than %d characters.", MAX_TITLE_LENGTH));
179             }
180             body.addFieldPart(MESSAGE_KEY_TITLE, new StringContentProvider(title), null);
181         }
182
183         if (device != null) {
184             if (device.length() > MAX_DEVICE_LENGTH) {
185                 logger.warn("Skip 'device' as it is longer than {} characters. Got: {}.", MAX_DEVICE_LENGTH, device);
186             } else {
187                 body.addFieldPart(MESSAGE_KEY_DEVICE, new StringContentProvider(device), null);
188             }
189         }
190
191         if (priority != DEFAULT_PRIORITY) {
192             if (VALID_PRIORITY_LIST.contains(priority)) {
193                 body.addFieldPart(MESSAGE_KEY_PRIORITY, new StringContentProvider(String.valueOf(priority)), null);
194
195                 if (priority == EMERGENCY_PRIORITY) {
196                     if (retry < MIN_RETRY_SECONDS) {
197                         logger.warn("Retry value of {} is too small. Using default value of {}.", retry,
198                                 MIN_RETRY_SECONDS);
199                         body.addFieldPart(MESSAGE_KEY_RETRY,
200                                 new StringContentProvider(String.valueOf(MIN_RETRY_SECONDS)), null);
201                     } else {
202                         body.addFieldPart(MESSAGE_KEY_RETRY, new StringContentProvider(String.valueOf(retry)), null);
203                     }
204
205                     if (0 < expire && expire <= MAX_EXPIRE_SECONDS) {
206                         body.addFieldPart(MESSAGE_KEY_EXPIRE, new StringContentProvider(String.valueOf(expire)), null);
207                     } else {
208                         logger.warn("Expire value of {} is invalid. Using default value of {}.", expire,
209                                 MAX_EXPIRE_SECONDS);
210                         body.addFieldPart(MESSAGE_KEY_EXPIRE,
211                                 new StringContentProvider(String.valueOf(MAX_EXPIRE_SECONDS)), null);
212                     }
213                 }
214             } else {
215                 logger.warn("Invalid 'priority', skipping. Expected: {}. Got: {}.",
216                         VALID_PRIORITY_LIST.stream().map(i -> i.toString()).collect(Collectors.joining(",")), priority);
217             }
218         }
219
220         if (url != null) {
221             if (url.length() > MAX_URL_LENGTH) {
222                 throw new IllegalArgumentException(String
223                         .format("Skip sending the message as 'url' is longer than %d characters.", MAX_URL_LENGTH));
224             }
225             body.addFieldPart(MESSAGE_KEY_URL, new StringContentProvider(url), null);
226
227             if (urlTitle != null) {
228                 if (urlTitle.length() > MAX_URL_TITLE_LENGTH) {
229                     throw new IllegalArgumentException(
230                             String.format("Skip sending the message as 'urlTitle' is longer than %d characters.",
231                                     MAX_URL_TITLE_LENGTH));
232                 }
233                 body.addFieldPart(MESSAGE_KEY_URL_TITLE, new StringContentProvider(urlTitle), null);
234             }
235         }
236
237         if (sound != null) {
238             body.addFieldPart(MESSAGE_KEY_SOUND, new StringContentProvider(sound), null);
239         }
240
241         if (attachment != null) {
242             File file = new File(attachment);
243             if (!file.exists()) {
244                 throw new IllegalArgumentException(
245                         String.format("Skip sending the message as file '%s' does not exist.", attachment));
246             }
247             try {
248                 body.addFilePart(MESSAGE_KEY_ATTACHMENT, file.getName(),
249                         new PathContentProvider(contentType, file.toPath()), null);
250             } catch (IOException e) {
251                 throw new IllegalArgumentException(String.format("Skip sending the message: %s", e.getMessage()));
252             }
253         }
254
255         if (html) {
256             body.addFieldPart(MESSAGE_KEY_HTML, new StringContentProvider("1"), null);
257         } else if (monospace) {
258             body.addFieldPart(MESSAGE_KEY_MONOSPACE, new StringContentProvider("1"), null);
259         }
260
261         return body;
262     }
263 }