1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package javax.mail;
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.PrintStream;
29 import java.lang.reflect.Constructor;
30 import java.lang.reflect.InvocationTargetException;
31 import java.net.InetAddress;
32 import java.net.URL;
33 import java.util.ArrayList;
34 import java.util.Enumeration;
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Properties;
39 import java.util.StringTokenizer;
40 import java.util.WeakHashMap;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public final class Session {
57 private static final Class[] PARAM_TYPES = {Session.class, URLName.class};
58 private static final WeakHashMap addressMapsByClassLoader = new WeakHashMap();
59 private static Session DEFAULT_SESSION;
60
61 private Map passwordAuthentications = new HashMap();
62
63 private final Properties properties;
64 private final Authenticator authenticator;
65 private boolean debug;
66 private PrintStream debugOut = System.out;
67
68 private static final WeakHashMap providersByClassLoader = new WeakHashMap();
69
70
71
72
73 private Session(Properties properties, Authenticator authenticator) {
74 this.properties = properties;
75 this.authenticator = authenticator;
76 debug = Boolean.valueOf(properties.getProperty("mail.debug")).booleanValue();
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 public static Session getInstance(Properties properties, Authenticator authenticator) {
97 return new Session(new Properties(properties), authenticator);
98 }
99
100
101
102
103
104
105
106
107 public static Session getInstance(Properties properties) {
108 return getInstance(properties, null);
109 }
110
111
112
113
114
115
116
117
118 public synchronized static Session getDefaultInstance(Properties properties) {
119 return getDefaultInstance(properties, null);
120 }
121
122
123
124
125
126
127
128
129
130
131 public synchronized static Session getDefaultInstance(Properties properties, Authenticator authenticator) {
132 if (DEFAULT_SESSION == null) {
133 DEFAULT_SESSION = getInstance(properties, authenticator);
134 } else {
135 if (authenticator != DEFAULT_SESSION.authenticator) {
136 if (authenticator == null || DEFAULT_SESSION.authenticator == null || authenticator.getClass().getClassLoader() != DEFAULT_SESSION.authenticator.getClass().getClassLoader()) {
137 throw new SecurityException();
138 }
139 }
140
141 }
142 return DEFAULT_SESSION;
143 }
144
145
146
147
148
149
150
151
152 public void setDebug(boolean debug) {
153 this.debug = debug;
154 }
155
156
157
158
159
160
161 public boolean getDebug() {
162 return debug;
163 }
164
165
166
167
168
169
170
171 public void setDebugOut(PrintStream out) {
172 debugOut = out == null ? System.out : out;
173 }
174
175
176
177
178
179
180 public PrintStream getDebugOut() {
181 return debugOut;
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195 public Provider[] getProviders() {
196 ProviderInfo info = getProviderInfo();
197 return (Provider[]) info.all.toArray(new Provider[info.all.size()]);
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212 public Provider getProvider(String protocol) throws NoSuchProviderException {
213 ProviderInfo info = getProviderInfo();
214 Provider provider = null;
215 String providerName = properties.getProperty("mail." + protocol + ".class");
216 if (providerName != null) {
217 provider = (Provider) info.byClassName.get(providerName);
218 if (debug) {
219 writeDebug("DEBUG: new provider loaded: " + provider.toString());
220 }
221 }
222
223
224 if (provider == null) {
225 provider = (Provider) info.byProtocol.get(protocol);
226 }
227
228 if (provider == null) {
229 throw new NoSuchProviderException("Unable to locate provider for protocol: " + protocol);
230 }
231 if (debug) {
232 writeDebug("DEBUG: getProvider() returning provider " + provider.toString());
233 }
234 return provider;
235 }
236
237
238
239
240
241
242
243 public void setProvider(Provider provider) throws NoSuchProviderException {
244 ProviderInfo info = getProviderInfo();
245 info.byProtocol.put(provider.getProtocol(), provider);
246 }
247
248
249
250
251
252
253
254 public Store getStore() throws NoSuchProviderException {
255 String protocol = properties.getProperty("mail.store.protocol");
256 if (protocol == null) {
257 throw new NoSuchProviderException("mail.store.protocol property is not set");
258 }
259 return getStore(protocol);
260 }
261
262
263
264
265
266
267
268
269 public Store getStore(String protocol) throws NoSuchProviderException {
270 Provider provider = getProvider(protocol);
271 return getStore(provider);
272 }
273
274
275
276
277
278
279
280
281 public Store getStore(URLName url) throws NoSuchProviderException {
282 return (Store) getService(getProvider(url.getProtocol()), url);
283 }
284
285
286
287
288
289
290
291
292 public Store getStore(Provider provider) throws NoSuchProviderException {
293 if (Provider.Type.STORE != provider.getType()) {
294 throw new NoSuchProviderException("Not a Store Provider: " + provider);
295 }
296 return (Store) getService(provider, null);
297 }
298
299
300
301
302
303
304
305
306
307
308
309
310 public Folder getFolder(URLName name) throws MessagingException {
311 Store store = getStore(name);
312 return store.getFolder(name);
313 }
314
315
316
317
318
319
320
321
322 public Transport getTransport() throws NoSuchProviderException {
323 String protocol = properties.getProperty("mail.transport.protocol");
324 if (protocol == null) {
325 throw new NoSuchProviderException("mail.transport.protocol property is not set");
326 }
327 return getTransport(protocol);
328 }
329
330
331
332
333
334
335
336
337 public Transport getTransport(String protocol) throws NoSuchProviderException {
338 Provider provider = getProvider(protocol);
339 return getTransport(provider);
340 }
341
342
343
344
345
346
347
348
349 public Transport getTransport(URLName name) throws NoSuchProviderException {
350 return (Transport) getService(getProvider(name.getProtocol()), name);
351 }
352
353
354
355
356
357
358
359
360 public Transport getTransport(Address address) throws NoSuchProviderException {
361 String type = address.getType();
362
363 Map addressMap = getAddressMap();
364 String protocolName = (String)addressMap.get(type);
365 if (protocolName == null) {
366 throw new NoSuchProviderException("No provider for address type " + type);
367 }
368 return getTransport(protocolName);
369 }
370
371
372
373
374
375
376
377
378 public Transport getTransport(Provider provider) throws NoSuchProviderException {
379 return (Transport) getService(provider, null);
380 }
381
382
383
384
385
386
387
388 public void setPasswordAuthentication(URLName name, PasswordAuthentication authenticator) {
389 if (authenticator == null) {
390 passwordAuthentications.remove(name);
391 } else {
392 passwordAuthentications.put(name, authenticator);
393 }
394 }
395
396
397
398
399
400
401
402 public PasswordAuthentication getPasswordAuthentication(URLName name) {
403 return (PasswordAuthentication) passwordAuthentications.get(name);
404 }
405
406
407
408
409
410
411
412
413
414
415
416 public PasswordAuthentication requestPasswordAuthentication(InetAddress host, int port, String protocol, String prompt, String defaultUserName) {
417 if (authenticator == null) {
418 return null;
419 }
420 return authenticator.authenticate(host, port, protocol, prompt, defaultUserName);
421 }
422
423
424
425
426
427
428 public Properties getProperties() {
429 return properties;
430 }
431
432
433
434
435
436
437
438 public String getProperty(String property) {
439 return getProperties().getProperty(property);
440 }
441
442
443
444
445
446
447
448 public synchronized void addProvider(Provider provider) {
449 ProviderInfo info = getProviderInfo();
450 info.addProvider(provider);
451 }
452
453
454
455
456
457
458
459
460
461
462
463 public void setProtocolForAddress(String addressType, String protocol) {
464 Map addressMap = getAddressMap();
465
466
467 if (protocol == null) {
468 addressMap.remove(addressType);
469 }
470 else {
471 addressMap.put(addressType, protocol);
472 }
473 }
474
475
476 private Service getService(Provider provider, URLName name) throws NoSuchProviderException {
477 try {
478 if (name == null) {
479 name = new URLName(provider.getProtocol(), null, -1, null, null, null);
480 }
481 ClassLoader cl = getClassLoader();
482 Class clazz = cl.loadClass(provider.getClassName());
483 Constructor ctr = clazz.getConstructor(PARAM_TYPES);
484 return (Service) ctr.newInstance(new Object[]{this, name});
485 } catch (ClassNotFoundException e) {
486 throw (NoSuchProviderException) new NoSuchProviderException("Unable to load class for provider: " + provider).initCause(e);
487 } catch (NoSuchMethodException e) {
488 throw (NoSuchProviderException) new NoSuchProviderException("Provider class does not have a constructor(Session, URLName): " + provider).initCause(e);
489 } catch (InstantiationException e) {
490 throw (NoSuchProviderException) new NoSuchProviderException("Unable to instantiate provider class: " + provider).initCause(e);
491 } catch (IllegalAccessException e) {
492 throw (NoSuchProviderException) new NoSuchProviderException("Unable to instantiate provider class: " + provider).initCause(e);
493 } catch (InvocationTargetException e) {
494 throw (NoSuchProviderException) new NoSuchProviderException("Exception from constructor of provider class: " + provider).initCause(e.getCause());
495 }
496 }
497
498 private ProviderInfo getProviderInfo() {
499 ClassLoader cl = getClassLoader();
500 ProviderInfo info = (ProviderInfo) providersByClassLoader.get(cl);
501 if (info == null) {
502 info = loadProviders(cl);
503 }
504 return info;
505 }
506
507 private Map getAddressMap() {
508 ClassLoader cl = getClassLoader();
509 Map addressMap = (Map)addressMapsByClassLoader.get(cl);
510 if (addressMap == null) {
511 addressMap = loadAddressMap(cl);
512 }
513 return addressMap;
514 }
515
516
517
518
519
520
521
522
523
524
525
526 private ClassLoader getClassLoader() {
527 ClassLoader cl = Thread.currentThread().getContextClassLoader();
528 if (cl == null) {
529 if (authenticator != null) {
530 cl = authenticator.getClass().getClassLoader();
531 }
532 else {
533 cl = this.getClass().getClassLoader();
534 }
535 }
536 return cl;
537 }
538
539 private ProviderInfo loadProviders(ClassLoader cl) {
540
541
542
543
544
545
546 ProviderInfo info = new ProviderInfo();
547
548
549 providersByClassLoader.put(cl, info);
550
551
552
553
554
555 try {
556 File file = new File(System.getProperty("java.home"), "lib/javamail.providers");
557 InputStream is = new FileInputStream(file);
558 try {
559 loadProviders(info, is);
560 if (debug) {
561 writeDebug("Loaded lib/javamail.providers from " + file.toString());
562 }
563 } finally{
564 is.close();
565 }
566 } catch (SecurityException e) {
567
568 } catch (IOException e) {
569
570 }
571
572 try {
573 Enumeration e = cl.getResources("META-INF/javamail.providers");
574 while (e.hasMoreElements()) {
575 URL url = (URL) e.nextElement();
576 if (debug) {
577 writeDebug("Loading META-INF/javamail.providers from " + url.toString());
578 }
579 InputStream is = url.openStream();
580 try {
581 loadProviders(info, is);
582 } finally{
583 is.close();
584 }
585 }
586 } catch (SecurityException e) {
587
588 } catch (IOException e) {
589
590 }
591
592 try {
593 Enumeration e = cl.getResources("META-INF/javamail.default.providers");
594 while (e.hasMoreElements()) {
595 URL url = (URL) e.nextElement();
596 if (debug) {
597 writeDebug("Loading javamail.default.providers from " + url.toString());
598 }
599
600 InputStream is = url.openStream();
601 try {
602 loadProviders(info, is);
603 } finally{
604 is.close();
605 }
606 }
607 } catch (SecurityException e) {
608
609 } catch (IOException e) {
610
611 }
612
613 return info;
614 }
615
616 private void loadProviders(ProviderInfo info, InputStream is) throws IOException {
617 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
618 String line;
619 while ((line = reader.readLine()) != null) {
620
621 if (line.startsWith("#")) {
622 continue;
623 }
624
625 StringTokenizer tok = new StringTokenizer(line, ";");
626 String protocol = null;
627 Provider.Type type = null;
628 String className = null;
629 String vendor = null;
630 String version = null;
631 while (tok.hasMoreTokens()) {
632 String property = tok.nextToken();
633 int index = property.indexOf('=');
634 if (index == -1) {
635 continue;
636 }
637 String key = property.substring(0, index).trim().toLowerCase();
638 String value = property.substring(index+1).trim();
639 if (protocol == null && "protocol".equals(key)) {
640 protocol = value;
641 } else if (type == null && "type".equals(key)) {
642 if ("store".equals(value)) {
643 type = Provider.Type.STORE;
644 } else if ("transport".equals(value)) {
645 type = Provider.Type.TRANSPORT;
646 }
647 } else if (className == null && "class".equals(key)) {
648 className = value;
649 } else if ("vendor".equals(key)) {
650 vendor = value;
651 } else if ("version".equals(key)) {
652 version = value;
653 }
654 }
655 if (protocol == null || type == null || className == null) {
656
657 continue;
658 }
659
660 if (debug) {
661 writeDebug("DEBUG: loading new provider protocol=" + protocol + ", className=" + className + ", vendor=" + vendor + ", version=" + version);
662 }
663 Provider provider = new Provider(type, protocol, className, vendor, version);
664
665 info.addProvider(provider);
666 }
667 }
668
669
670
671
672
673
674
675
676
677
678 private static Map loadAddressMap(ClassLoader cl) {
679
680
681
682
683
684
685
686
687
688
689 Properties addressMap = new Properties();
690
691
692 addressMapsByClassLoader.put(cl, addressMap);
693
694
695
696
697 try {
698 Enumeration e = cl.getResources("META-INF/javamail.default.address.map");
699 while (e.hasMoreElements()) {
700 URL url = (URL) e.nextElement();
701 InputStream is = url.openStream();
702 try {
703
704 addressMap.load(is);
705 } finally{
706 is.close();
707 }
708 }
709 } catch (SecurityException e) {
710
711 } catch (IOException e) {
712
713 }
714
715
716 try {
717 Enumeration e = cl.getResources("META-INF/javamail.address.map");
718 while (e.hasMoreElements()) {
719 URL url = (URL) e.nextElement();
720 InputStream is = url.openStream();
721 try {
722
723 addressMap.load(is);
724 } finally{
725 is.close();
726 }
727 }
728 } catch (SecurityException e) {
729
730 } catch (IOException e) {
731
732 }
733
734
735 try {
736 File file = new File(System.getProperty("java.home"), "lib/javamail.address.map");
737 InputStream is = new FileInputStream(file);
738 try {
739
740 addressMap.load(is);
741 } finally{
742 is.close();
743 }
744 } catch (SecurityException e) {
745
746 } catch (IOException e) {
747
748 }
749
750 try {
751 Enumeration e = cl.getResources("META-INF/javamail.address.map");
752 while (e.hasMoreElements()) {
753 URL url = (URL) e.nextElement();
754 InputStream is = url.openStream();
755 try {
756
757 addressMap.load(is);
758 } finally{
759 is.close();
760 }
761 }
762 } catch (SecurityException e) {
763
764 } catch (IOException e) {
765
766 }
767
768
769
770 if (addressMap.isEmpty()) {
771 addressMap.put("rfc822", "smtp");
772 }
773
774 return addressMap;
775 }
776
777
778
779
780
781
782 private void writeDebug(String msg) {
783 debugOut.println(msg);
784 }
785
786
787 private static class ProviderInfo {
788 private final Map byClassName = new HashMap();
789 private final Map byProtocol = new HashMap();
790 private final List all = new ArrayList();
791
792 public void addProvider(Provider provider) {
793 String className = provider.getClassName();
794
795 if (!byClassName.containsKey(className)) {
796 byClassName.put(className, provider);
797 }
798
799 String protocol = provider.getProtocol();
800 if (!byProtocol.containsKey(protocol)) {
801 byProtocol.put(protocol, provider);
802 }
803 all.add(provider);
804 }
805 }
806 }