1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
|
29 | |
|
30 | |
package com.jcabi.email; |
31 | |
|
32 | |
import com.google.common.cache.Cache; |
33 | |
import com.google.common.cache.CacheBuilder; |
34 | |
import com.jcabi.aspects.Immutable; |
35 | |
import com.jcabi.aspects.Loggable; |
36 | |
import com.jcabi.immutable.Array; |
37 | |
import com.jcabi.log.Logger; |
38 | |
import java.io.IOException; |
39 | |
import java.util.Properties; |
40 | |
import java.util.concurrent.Callable; |
41 | |
import java.util.concurrent.ExecutionException; |
42 | |
import java.util.concurrent.TimeUnit; |
43 | |
import javax.mail.Flags; |
44 | |
import javax.mail.Message; |
45 | |
import javax.mail.MessagingException; |
46 | |
import javax.mail.Multipart; |
47 | |
import javax.mail.Session; |
48 | |
import javax.mail.internet.InternetAddress; |
49 | |
import javax.mail.internet.MimeMessage; |
50 | |
import javax.mail.internet.MimeMultipart; |
51 | |
import lombok.EqualsAndHashCode; |
52 | |
import lombok.ToString; |
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
@Immutable |
68 | |
public interface Envelope { |
69 | |
|
70 | |
|
71 | |
|
72 | |
|
73 | |
|
74 | 1 | Envelope EMPTY = new Envelope() { |
75 | |
@Override |
76 | |
public Message unwrap() { |
77 | 7 | return new MimeMessage( |
78 | |
Session.getDefaultInstance(new Properties()) |
79 | |
); |
80 | |
} |
81 | |
}; |
82 | |
|
83 | |
|
84 | |
|
85 | |
|
86 | |
|
87 | |
|
88 | |
Message unwrap() throws IOException; |
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
@Immutable |
94 | 0 | @ToString |
95 | 0 | @EqualsAndHashCode(of = "encs") |
96 | |
@Loggable(Loggable.DEBUG) |
97 | |
final class MIME implements Envelope { |
98 | |
|
99 | |
|
100 | |
|
101 | |
private final transient Array<Stamp> stamps; |
102 | |
|
103 | |
|
104 | |
|
105 | |
private final transient Array<Enclosure> encs; |
106 | |
|
107 | |
|
108 | |
|
109 | |
|
110 | |
public MIME() { |
111 | 7 | this(new Array<Stamp>(), new Array<Enclosure>()); |
112 | 7 | } |
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
|
118 | |
public MIME(final Envelope env) { |
119 | 2 | this( |
120 | |
Envelope.MIME.class.cast(env).stamps, |
121 | |
Envelope.MIME.class.cast(env).encs |
122 | |
); |
123 | 2 | } |
124 | |
|
125 | |
|
126 | |
|
127 | |
|
128 | |
|
129 | |
public MIME(final Iterable<Stamp> stmps, |
130 | 33 | final Iterable<Enclosure> list) { |
131 | 33 | this.stamps = new Array<>(stmps); |
132 | 33 | this.encs = new Array<>(list); |
133 | 33 | } |
134 | |
@Override |
135 | |
public Message unwrap() throws IOException { |
136 | 7 | final Message msg = Envelope.EMPTY.unwrap(); |
137 | 7 | final Multipart multi = new MimeMultipart("alternative"); |
138 | |
try { |
139 | 7 | for (final Enclosure enc : this.encs) { |
140 | 6 | multi.addBodyPart(enc.part()); |
141 | 6 | } |
142 | 7 | for (final Stamp stamp : this.stamps) { |
143 | 18 | stamp.attach(msg); |
144 | 18 | } |
145 | 7 | msg.setContent(multi); |
146 | 0 | } catch (final MessagingException ex) { |
147 | 0 | throw new IOException(ex); |
148 | 7 | } |
149 | 7 | return msg; |
150 | |
} |
151 | |
|
152 | |
|
153 | |
|
154 | |
|
155 | |
|
156 | |
|
157 | |
public Envelope.MIME with(final Stamp stamp) { |
158 | 18 | return new Envelope.MIME( |
159 | |
this.stamps.with(stamp), |
160 | |
this.encs |
161 | |
); |
162 | |
} |
163 | |
|
164 | |
|
165 | |
|
166 | |
|
167 | |
|
168 | |
|
169 | |
public Envelope.MIME with(final Enclosure enc) { |
170 | 6 | return new Envelope.MIME( |
171 | |
this.stamps, |
172 | |
this.encs.with(enc) |
173 | |
); |
174 | |
} |
175 | |
} |
176 | |
|
177 | |
|
178 | |
|
179 | |
|
180 | |
|
181 | |
@Immutable |
182 | 0 | @ToString |
183 | 0 | @EqualsAndHashCode(of = "origin") |
184 | |
@Loggable(Loggable.DEBUG) |
185 | |
final class Strict implements Envelope { |
186 | |
|
187 | |
|
188 | |
|
189 | |
private final transient Envelope origin; |
190 | |
|
191 | |
|
192 | |
|
193 | |
|
194 | 2 | public Strict(final Envelope env) { |
195 | 2 | this.origin = env; |
196 | 2 | } |
197 | |
@Override |
198 | |
public Message unwrap() throws IOException { |
199 | 2 | final Message msg = this.origin.unwrap(); |
200 | |
try { |
201 | 2 | if (msg.getAllRecipients() == null) { |
202 | 0 | throw new IllegalStateException( |
203 | |
"list of recipients is NULL" |
204 | |
); |
205 | |
} |
206 | 2 | if (msg.getFrom() == null) { |
207 | 0 | throw new IllegalStateException( |
208 | |
"list of senders is NULL" |
209 | |
); |
210 | |
} |
211 | 2 | if (msg.getSubject() == null) { |
212 | 0 | throw new IllegalStateException( |
213 | |
"subject is NULL" |
214 | |
); |
215 | |
} |
216 | 0 | } catch (final MessagingException ex) { |
217 | 0 | throw new IOException(ex); |
218 | 2 | } |
219 | 2 | return msg; |
220 | |
} |
221 | |
} |
222 | |
|
223 | |
|
224 | |
|
225 | |
|
226 | |
|
227 | |
@Immutable |
228 | 0 | @ToString |
229 | 0 | @EqualsAndHashCode(of = "origin") |
230 | |
@Loggable(Loggable.DEBUG) |
231 | |
final class Safe implements Envelope { |
232 | |
|
233 | |
|
234 | |
|
235 | |
private final transient Envelope origin; |
236 | |
|
237 | |
|
238 | |
|
239 | |
|
240 | 2 | public Safe(final Envelope env) { |
241 | 2 | this.origin = env; |
242 | 2 | } |
243 | |
@Override |
244 | |
public Message unwrap() throws IOException { |
245 | 2 | final Message msg = this.origin.unwrap(); |
246 | |
try { |
247 | 2 | if (msg.getAllRecipients() == null) { |
248 | 0 | msg.addRecipient( |
249 | |
Message.RecipientType.TO, |
250 | |
new InternetAddress("to@example.com") |
251 | |
); |
252 | 0 | Logger.warn(this, "recipients were NULL, fake one set"); |
253 | |
} |
254 | 2 | if (msg.getFrom() == null) { |
255 | 0 | msg.setFrom(new InternetAddress("from@example.com")); |
256 | 0 | Logger.warn(this, "senders were NULL, fake one set"); |
257 | |
} |
258 | 2 | if (msg.getSubject() == null) { |
259 | 0 | msg.setSubject(this.getClass().getCanonicalName()); |
260 | 0 | Logger.warn(this, "subject was NULL, fake one set"); |
261 | |
} |
262 | 0 | } catch (final MessagingException ex) { |
263 | 0 | throw new IOException(ex); |
264 | 2 | } |
265 | 2 | return msg; |
266 | |
} |
267 | |
} |
268 | |
|
269 | |
|
270 | |
|
271 | |
|
272 | |
|
273 | |
@Immutable |
274 | 0 | @ToString |
275 | 0 | @EqualsAndHashCode(of = "origin") |
276 | |
@Loggable(Loggable.DEBUG) |
277 | 1 | final class Constant implements Envelope { |
278 | |
|
279 | |
|
280 | |
|
281 | 1 | private static final Cache<Envelope, Message> CACHE = |
282 | |
CacheBuilder.newBuilder() |
283 | |
.expireAfterWrite(1L, TimeUnit.HOURS) |
284 | |
.build(); |
285 | |
|
286 | |
|
287 | |
|
288 | |
private final transient Envelope origin; |
289 | |
|
290 | |
|
291 | |
|
292 | |
|
293 | 1 | public Constant(final Envelope env) { |
294 | 1 | this.origin = env; |
295 | 1 | } |
296 | |
@Override |
297 | |
public Message unwrap() throws IOException { |
298 | |
try { |
299 | 2 | return Envelope.Constant.CACHE.get( |
300 | |
this.origin, |
301 | 3 | new Callable<Message>() { |
302 | |
@Override |
303 | |
public Message call() throws Exception { |
304 | 1 | return Envelope.Constant.this.origin.unwrap(); |
305 | |
} |
306 | |
} |
307 | |
); |
308 | 0 | } catch (final ExecutionException ex) { |
309 | 0 | throw new IOException(ex); |
310 | |
} |
311 | |
} |
312 | |
} |
313 | |
|
314 | |
|
315 | |
|
316 | |
|
317 | |
|
318 | |
@Immutable |
319 | 0 | @ToString |
320 | 0 | @EqualsAndHashCode(of = "env") |
321 | |
@Loggable(Loggable.DEBUG) |
322 | |
final class Draft implements Envelope { |
323 | |
|
324 | |
|
325 | |
|
326 | |
private final transient Envelope env; |
327 | |
|
328 | |
|
329 | |
|
330 | |
|
331 | 0 | public Draft(final Envelope origin) { |
332 | 0 | this.env = origin; |
333 | 0 | } |
334 | |
@Override |
335 | |
public Message unwrap() throws IOException { |
336 | 0 | final Message msg = this.env.unwrap(); |
337 | |
try { |
338 | 0 | msg.setFlag(Flags.Flag.DRAFT, true); |
339 | 0 | } catch (final MessagingException ex) { |
340 | 0 | throw new IOException(ex); |
341 | 0 | } |
342 | 0 | return msg; |
343 | |
} |
344 | |
} |
345 | |
|
346 | |
} |