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 synchronized (providersByClassLoader) {
501 ProviderInfo info = (ProviderInfo) providersByClassLoader.get(cl);
502 if (info == null) {
503 info = loadProviders(cl);
504 }
505 return info;
506 }
507 }
508
509 private Map getAddressMap() {
510 ClassLoader cl = getClassLoader();
511 Map addressMap = (Map)addressMapsByClassLoader.get(cl);
512 if (addressMap == null) {
513 addressMap = loadAddressMap(cl);
514 }
515 return addressMap;
516 }
517
518
519
520
521
522
523
524
525
526
527
528 private ClassLoader getClassLoader() {
529 ClassLoader cl = Thread.currentThread().getContextClassLoader();
530 if (cl == null) {
531 if (authenticator != null) {
532 cl = authenticator.getClass().getClassLoader();
533 }
534 else {
535 cl = this.getClass().getClassLoader();
536 }
537 }
538 return cl;
539 }
540
541 private ProviderInfo loadProviders(ClassLoader cl) {
542
543
544
545
546
547
548 ProviderInfo info = new ProviderInfo();
549
550
551
552
553 try {
554 File file = new File(System.getProperty("java.home"), "lib/javamail.providers");
555 InputStream is = new FileInputStream(file);
556 try {
557 loadProviders(info, is);
558 if (debug) {
559 writeDebug("Loaded lib/javamail.providers from " + file.toString());
560 }
561 } finally{
562 is.close();
563 }
564 } catch (SecurityException e) {
565
566 } catch (IOException e) {
567
568 }
569
570 try {
571 Enumeration e = cl.getResources("META-INF/javamail.providers");
572 while (e.hasMoreElements()) {
573 URL url = (URL) e.nextElement();
574 if (debug) {
575 writeDebug("Loading META-INF/javamail.providers from " + url.toString());
576 }
577 InputStream is = url.openStream();
578 try {
579 loadProviders(info, is);
580 } finally{
581 is.close();
582 }
583 }
584 } catch (SecurityException e) {
585
586 } catch (IOException e) {
587
588 }
589
590 try {
591 Enumeration e = cl.getResources("META-INF/javamail.default.providers");
592 while (e.hasMoreElements()) {
593 URL url = (URL) e.nextElement();
594 if (debug) {
595 writeDebug("Loading javamail.default.providers from " + url.toString());
596 }
597
598 InputStream is = url.openStream();
599 try {
600 loadProviders(info, is);
601 } finally{
602 is.close();
603 }
604 }
605 } catch (SecurityException e) {
606
607 } catch (IOException e) {
608
609 }
610
611
612 providersByClassLoader.put(cl, info);
613
614 return info;
615 }
616
617 private void loadProviders(ProviderInfo info, InputStream is) throws IOException {
618 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
619 String line;
620 while ((line = reader.readLine()) != null) {
621
622 if (line.startsWith("#")) {
623 continue;
624 }
625
626 StringTokenizer tok = new StringTokenizer(line, ";");
627 String protocol = null;
628 Provider.Type type = null;
629 String className = null;
630 String vendor = null;
631 String version = null;
632 while (tok.hasMoreTokens()) {
633 String property = tok.nextToken();
634 int index = property.indexOf('=');
635 if (index == -1) {
636 continue;
637 }
638 String key = property.substring(0, index).trim().toLowerCase();
639 String value = property.substring(index+1).trim();
640 if (protocol == null && "protocol".equals(key)) {
641 protocol = value;
642 } else if (type == null && "type".equals(key)) {
643 if ("store".equals(value)) {
644 type = Provider.Type.STORE;
645 } else if ("transport".equals(value)) {
646 type = Provider.Type.TRANSPORT;
647 }
648 } else if (className == null && "class".equals(key)) {
649 className = value;
650 } else if ("vendor".equals(key)) {
651 vendor = value;
652 } else if ("version".equals(key)) {
653 version = value;
654 }
655 }
656 if (protocol == null || type == null || className == null) {
657
658 continue;
659 }
660
661 if (debug) {
662 writeDebug("DEBUG: loading new provider protocol=" + protocol + ", className=" + className + ", vendor=" + vendor + ", version=" + version);
663 }
664 Provider provider = new Provider(type, protocol, className, vendor, version);
665
666 info.addProvider(provider);
667 }
668 }
669
670
671
672
673
674
675
676
677
678
679 private static Map loadAddressMap(ClassLoader cl) {
680
681
682
683
684
685
686
687
688
689
690 Properties addressMap = new Properties();
691
692
693 addressMapsByClassLoader.put(cl, addressMap);
694
695
696
697
698 try {
699 Enumeration e = cl.getResources("META-INF/javamail.default.address.map");
700 while (e.hasMoreElements()) {
701 URL url = (URL) e.nextElement();
702 InputStream is = url.openStream();
703 try {
704
705 addressMap.load(is);
706 } finally{
707 is.close();
708 }
709 }
710 } catch (SecurityException e) {
711
712 } catch (IOException e) {
713
714 }
715
716
717 try {
718 Enumeration e = cl.getResources("META-INF/javamail.address.map");
719 while (e.hasMoreElements()) {
720 URL url = (URL) e.nextElement();
721 InputStream is = url.openStream();
722 try {
723
724 addressMap.load(is);
725 } finally{
726 is.close();
727 }
728 }
729 } catch (SecurityException e) {
730
731 } catch (IOException e) {
732
733 }
734
735
736 try {
737 File file = new File(System.getProperty("java.home"), "lib/javamail.address.map");
738 InputStream is = new FileInputStream(file);
739 try {
740
741 addressMap.load(is);
742 } finally{
743 is.close();
744 }
745 } catch (SecurityException e) {
746
747 } catch (IOException e) {
748
749 }
750
751 try {
752 Enumeration e = cl.getResources("META-INF/javamail.address.map");
753 while (e.hasMoreElements()) {
754 URL url = (URL) e.nextElement();
755 InputStream is = url.openStream();
756 try {
757
758 addressMap.load(is);
759 } finally{
760 is.close();
761 }
762 }
763 } catch (SecurityException e) {
764
765 } catch (IOException e) {
766
767 }
768
769
770
771 if (addressMap.isEmpty()) {
772 addressMap.put("rfc822", "smtp");
773 }
774
775 return addressMap;
776 }
777
778
779
780
781
782
783 private void writeDebug(String msg) {
784 debugOut.println(msg);
785 }
786
787
788 private static class ProviderInfo {
789 private final Map byClassName = new HashMap();
790 private final Map byProtocol = new HashMap();
791 private final List all = new ArrayList();
792
793 public void addProvider(Provider provider) {
794 String className = provider.getClassName();
795
796 if (!byClassName.containsKey(className)) {
797 byClassName.put(className, provider);
798 }
799
800 String protocol = provider.getProtocol();
801 if (!byProtocol.containsKey(protocol)) {
802 byProtocol.put(protocol, provider);
803 }
804 all.add(provider);
805 }
806 }
807 }