View Javadoc

1   /*
2    * $Id: AbstractMailConnector.java 10489 2008-01-23 17:53:38Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport.email;
12  
13  import org.mule.api.MuleException;
14  import org.mule.api.endpoint.EndpointURI;
15  import org.mule.api.endpoint.ImmutableEndpoint;
16  import org.mule.api.lifecycle.InitialisationException;
17  import org.mule.transport.AbstractConnector;
18  import org.mule.util.StringUtils;
19  
20  import java.util.Enumeration;
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.Properties;
24  
25  import javax.mail.Authenticator;
26  import javax.mail.Session;
27  import javax.mail.URLName;
28  
29  /**
30   * Abstract superclass for mail connectors. Provides Mule with an Authenticator
31   * object and other shared functionality like e.g. MuleSession creation.
32   */
33  public abstract class AbstractMailConnector extends AbstractConnector
34  {
35  
36      public static final String MAILBOX = "INBOX";
37  
38      private Map sessions = new HashMap();
39      private String mailboxFolder;
40      private int defaultPort;
41  
42      /**
43       * A custom authenticator to be used on any mail sessions created with this
44       * connector. This will only be used if user name credendials are set on the
45       * endpoint.
46       */
47      private Authenticator authenticator = null;
48  
49      public AbstractMailConnector(int defaultPort, String mailboxFolder)
50      {
51          super();
52          this.defaultPort = defaultPort;
53          this.mailboxFolder = mailboxFolder;
54      }
55  
56      public int getDefaultPort()
57      {
58          return defaultPort;
59      }
60  
61      public Authenticator getAuthenticator()
62      {
63          return authenticator;
64      }
65  
66      public void setAuthenticator(Authenticator authenticator)
67      {
68          this.authenticator = authenticator;
69      }
70      
71      public String getMailboxFolder()
72      {
73          return mailboxFolder;
74      }
75  
76      public void setMailboxFolder(String mailboxFolder)
77      {
78          this.mailboxFolder = mailboxFolder;
79      }
80  
81      public synchronized SessionDetails getSessionDetails(ImmutableEndpoint endpoint)
82      {
83          SessionDetails sessionDetails = (SessionDetails) sessions.get(endpoint);
84          if (null == sessionDetails)
85          {
86              sessionDetails = newSession(endpoint);
87              sessions.put(endpoint, sessionDetails);
88          }
89          return sessionDetails;
90      }
91      
92      public URLName urlFromEndpoint(ImmutableEndpoint endpoint)
93      {
94          String inbox = endpoint.getEndpointURI().getPath();
95          if (inbox.length() == 0)
96          {
97              inbox = getMailboxFolder();
98          }
99          else
100         {
101             inbox = inbox.substring(1);
102         }
103 
104         EndpointURI uri = endpoint.getEndpointURI();
105         return new URLName(uri.getScheme(), uri.getHost(), uri.getPort(), inbox,
106                 uri.getUser(), uri.getPassword());
107     }
108     
109     /**
110      * Some protocols (eg secure extensions) extend a "base" protocol.
111      * Subclasses for such protocols should override this method.
112      * 
113      * @return the underlying (eg non-secure) protocol
114      */
115     protected String getBaseProtocol()
116     {
117         return getProtocol();
118     }
119     
120     /**
121      * Subclasses should extend this to add further properties.  
122      * Synchronization is managed outside this call (so no need to synchronize further on properties)
123      * 
124      * @param global system properties 
125      * @param local local properties (specific to one session)
126      * @param url the endpoint url
127      */
128     protected void extendPropertiesForSession(Properties global, Properties local, URLName url)
129     {
130         int port = url.getPort();
131         if (port == -1)
132         {
133             port = this.getDefaultPort();
134         }
135         local.setProperty("mail." + getBaseProtocol() + ".socketFactory.port", Integer.toString(port));
136 
137         if (StringUtils.isNotBlank(url.getPassword()))
138         {
139             local.setProperty("mail." + getBaseProtocol() + ".auth", "true");
140             if (getAuthenticator() == null)
141             {
142                 setAuthenticator(new DefaultAuthenticator(url.getUsername(), url.getPassword()));
143                 if (logger.isDebugEnabled())
144                 {
145                     logger.debug("No Authenticator set on connector: " + getName() + "; using default.");
146                 }
147             }
148         }
149         else
150         {
151             local.setProperty("mail." + getBaseProtocol() + ".auth", "false");
152         }
153         
154         // TODO - i'm not at all certain that these properties (especially the ones
155         // using the base protocol) are needed.  they are inherited from old, gnarly
156         // code.
157 
158         if (StringUtils.isNotBlank(url.getHost())) {
159             local.setProperty("mail." + getBaseProtocol() + ".host", url.getHost());
160         }
161         local.setProperty("mail." + getBaseProtocol() + ".rsetbeforequit", "true");
162     }
163 
164     protected SessionDetails newSession(ImmutableEndpoint endpoint)
165     {
166         URLName url = urlFromEndpoint(endpoint);
167 
168         Properties global = System.getProperties();
169         Properties local = new Properties();
170         Session session;
171 
172         // make sure we do not mess with authentication set via system properties
173         synchronized (global)
174         {
175             extendPropertiesForSession(global, local, url);
176             session = Session.getInstance(local, getAuthenticator());
177         }
178 
179         if (logger.isDebugEnabled())
180         {
181             local.setProperty("mail.debug", "true");
182             
183             dumpProperties("MuleSession local properties", local, true);
184             dumpProperties("System global properties", global, true);
185             logger.debug("Creating mail session: host = " + url.getHost() + ", port = " + url.getPort()
186                 + ", user = " + url.getUsername() + ", pass = " + url.getPassword());
187         }
188 
189         return new SessionDetails(session, url);
190     }
191     
192     protected void dumpProperties(String title, Properties properties, boolean filter)
193     {
194         int skipped = 0;
195         logger.debug(title + " =============");
196         Enumeration keys = properties.keys();
197         while (keys.hasMoreElements())
198         {
199             String key = (String) keys.nextElement();
200             if (!filter || key.startsWith("mule.") || key.startsWith("mail.") || key.startsWith("javax."))
201             {
202                 String value = properties.getProperty(key);
203                 logger.debug(key + ": " + value);
204             }
205             else 
206             {
207                 ++skipped;
208             }
209         }
210         if (filter)
211         {
212             logger.debug("skipped " + skipped);
213         }
214     }
215     
216     // supply these here because sub-classes are very simple
217 
218     protected void doInitialise() throws InitialisationException
219     {
220         // template method, nothing to do
221     }
222 
223     protected void doDispose()
224     {
225         // template method, nothing to do
226     }
227 
228     protected void doConnect() throws Exception
229     {
230         // template method, nothing to do
231     }
232 
233     protected void doDisconnect() throws Exception
234     {
235         // template method, nothing to do
236     }
237 
238     protected void doStart() throws MuleException
239     {
240         // template method, nothing to do
241     }
242 
243     protected void doStop() throws MuleException
244     {
245         // template method, nothing to do
246     }
247 
248 }