001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.mail;
018
019 import java.util.Collection;
020 import java.util.Iterator;
021 import java.util.Properties;
022
023 import javax.mail.Authenticator;
024 import javax.mail.Session;
025 import javax.naming.Context;
026 import javax.naming.InitialContext;
027 import javax.naming.Name;
028 import javax.naming.NamingException;
029
030 import org.apache.commons.logging.Log;
031 import org.apache.commons.logging.LogFactory;
032 import org.apache.geronimo.gbean.GBeanInfo;
033 import org.apache.geronimo.gbean.GBeanInfoBuilder;
034 import org.apache.geronimo.gbean.GBeanLifecycle;
035 import org.apache.geronimo.naming.ResourceSource;
036 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
037 import org.apache.geronimo.management.JavaMailResource;
038
039
040 /**
041 * GBean that provides access to JavaMail Sessions.
042 * <p/>
043 * This GBean is used to generate JavaMail Sessions. JavaMail properties that
044 * are common to all JavaMail Sessions are provided via member variables of this
045 * class.
046 *
047 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
048 * @see ProtocolGBean
049 * @see SMTPTransportGBean
050 * @see POP3StoreGBean
051 * @see IMAPStoreGBean
052 */
053 public class MailGBean implements GBeanLifecycle, JavaMailResource, ResourceSource {
054
055 private final Log log = LogFactory.getLog(MailGBean.class);
056
057 private final String objectName;
058 private final Collection protocols;
059 private Boolean useDefault;
060 private Properties properties;
061 private Authenticator authenticator;
062 private String storeProtocol;
063 private String transportProtocol;
064 private String host;
065 private String user;
066 private Boolean debug;
067 private String jndiName;
068
069
070 /**
071 * Construct an instance of MailGBean
072 * <p/>
073 * Values that are set in the individual member variables will override any of
074 * the corresponding values that have been set in the properties set.
075 *
076 * @param protocols the set of protocol GBeans that contain protocol specific configurations
077 * @param useDefault whether this GBean will return default Sessions or not
078 * @param properties the set of default properties for the protocols
079 * @param authenticator the authenticator object
080 * @param storeProtocol the store protocol that Sessions created from this GBean will return
081 * @param transportProtocol the transport protocol that Sessions created from this GBean will return
082 * @param host the default Mail server
083 * @param user the username to provide when connecting to a Mail server
084 * @param debug the debug setting for Sessions created from this GBean
085 * @param jndiName the JNDI name to which the mail Session should be bound
086 */
087 public MailGBean(String objectName, Collection protocols, Boolean useDefault, Properties properties, Authenticator authenticator,
088 String storeProtocol, String transportProtocol, String host, String user, Boolean debug, String jndiName) {
089 this.objectName = objectName;
090 this.protocols = protocols;
091 setUseDefault(useDefault);
092 this.properties = (properties == null ? new Properties() : properties);
093 setAuthenticator(authenticator);
094 setStoreProtocol(storeProtocol);
095 setTransportProtocol(transportProtocol);
096 setHost(host);
097 setUser(user);
098 setDebug(debug);
099 setJndiName(jndiName);
100 }
101
102 /**
103 * Returns the set of protocol GBeans that contain protocol specific configurations.
104 */
105 public Collection getProtocols() {
106 return protocols;
107 }
108
109 /**
110 * Returns whether this GBean will return default Sessions or not.
111 */
112 public Boolean getUseDefault() {
113 return useDefault;
114 }
115
116 /**
117 * Sets whether this GBean will return default Sessions or not,
118 *
119 * @param useDefault whether this GBean will return default Sessions or not
120 */
121 public void setUseDefault(Boolean useDefault) {
122 this.useDefault = useDefault;
123 }
124
125 /**
126 * Returns the set of default properties for the protocols.
127 * <p/>
128 * Note: Proerties that are set here will override the properties that are
129 * set in the protocol GBeans.
130 */
131 public Properties getProperties() {
132 return properties;
133 }
134
135 /**
136 * Sets the set of default properties for the protocols.
137 * <p/>
138 * Note: Proerties that are set here will override the properties that are
139 * set in the protocol GBeans.
140 *
141 * @param properties the set of default properties for the protocols
142 */
143 public void setProperties(Properties properties) {
144 this.properties = properties;
145 }
146
147 /**
148 * Returns the authenticator object.
149 * <p/>
150 * Used only if a new Session object is created. Otherwise, it must match
151 * the Authenticator used to create the Session.
152 */
153 public Authenticator getAuthenticator() {
154 return authenticator;
155 }
156
157 /**
158 * Sets the authenticator object.
159 * <p/>
160 * Used only if a new Session object is created. Otherwise, it must match
161 * the Authenticator used to create the Session.
162 *
163 * @param authenticator the authenticator object
164 */
165 public void setAuthenticator(Authenticator authenticator) {
166 this.authenticator = authenticator;
167 }
168
169 /**
170 * Returns the store protocol that Sessions created from this GBean will return.
171 * <p/>
172 * Specifies the default Message Access Protocol. The Session.getStore()
173 * method returns a Store object that implements this protocol. The client
174 * can override this property and explicitly specify the protocol with the
175 * Session.getStore(String protocol) method.
176 */
177 public String getStoreProtocol() {
178 return storeProtocol;
179 }
180
181 /**
182 * Sets the store protocol that Sessions created from this GBean will return.
183 * <p/>
184 * Specifies the default Message Access Protocol. The Session.getStore()
185 * method returns a Store object that implements this protocol. The client
186 * can override this property and explicitly specify the protocol with the
187 * Session.getStore(String protocol) method.
188 * <p/>
189 * Values that are set here will override any of the corresponding value
190 * that has been set in the properties.
191 *
192 * @param storeProtocol the store protocol that Sessions created from this GBean will return
193 */
194 public void setStoreProtocol(String storeProtocol) {
195 this.storeProtocol = storeProtocol;
196 }
197
198 /**
199 * Returns the transport protocol that Sessions created from this GBean will return.
200 * <p/>
201 * Specifies the default Transport Protocol. The Session.getTransport()
202 * method returns a Transport object that implements this protocol. The
203 * client can override this property and explicitly specify the protocol
204 * by using Session.getTransport(String protocol) method.
205 */
206 public String getTransportProtocol() {
207 return transportProtocol;
208 }
209
210 /**
211 * Sets the transport protocol that Sessions created from this GBean will return.
212 * <p/>
213 * Specifies the default Transport Protocol. The Session.getTransport()
214 * method returns a Transport object that implements this protocol. The
215 * client can override this property and explicitly specify the protocol
216 * by using Session.getTransport(String protocol) method.
217 * <p/>
218 * Values that are set here will override any of the corresponding value
219 * that has been set in the properties.
220 *
221 * @param transportProtocol the transport protocol that Sessions created from this GBean will return
222 */
223 public void setTransportProtocol(String transportProtocol) {
224 this.transportProtocol = transportProtocol;
225 }
226
227 /**
228 * Returns the default Mail server.
229 * <p/>
230 * Specifies the default Mail server. The Store and Transport object’s
231 * connect methods use this property, if the protocolspecific host property
232 * is absent, to locate the target host.
233 */
234 public String getHost() {
235 return host;
236 }
237
238 /**
239 * Sets the default Mail server.
240 * <p/>
241 * Specifies the default Mail server. The Store and Transport object’s
242 * connect methods use this property, if the protocolspecific host property
243 * is absent, to locate the target host.
244 * <p/>
245 * Values that are set here will override any of the corresponding value
246 * that has been set in the properties.
247 *
248 * @param host the default Mail server
249 */
250 public void setHost(String host) {
251 this.host = host;
252 }
253
254 /**
255 * Returns the username to provide when connecting to a Mail server.
256 * <p/>
257 * Specifies the username to provide when connecting to a Mail server. The
258 * Store and Transport object’s connect methods use this property, if the
259 * protocolspecific username property is absent, to obtain the username.
260 */
261 public String getUser() {
262 return user;
263 }
264
265 /**
266 * Sets the username to provide when connecting to a Mail server.
267 * <p/>
268 * Specifies the username to provide when connecting to a Mail server. The
269 * Store and Transport object’s connect methods use this property, if the
270 * protocolspecific username property is absent, to obtain the username.
271 * <p/>
272 * Values that are set here will override any of the corresponding value
273 * that has been set in the properties.
274 *
275 * @param user the username to provide when connecting to a Mail server
276 */
277 public void setUser(String user) {
278 this.user = user;
279 }
280
281 /**
282 * Returns the debug setting for Sessions created from this GBean.
283 */
284 public Boolean getDebug() {
285 return debug;
286 }
287
288 /**
289 * Sets the debug setting for Sessions created from this GBean.
290 * <p/>
291 * Values that are set here will override any of the corresponding value
292 * that has been set in the properties.
293 *
294 * @param debug the debug setting for Sessions created from this GBean
295 */
296 public void setDebug(Boolean debug) {
297 this.debug = debug;
298 }
299
300 /**
301 * Gets the JNDI name to which the mail Session should be bound
302 * @return the JNDI name to which the mail Session should be bound
303 */
304 public String getJndiName() {
305 return jndiName;
306 }
307
308 /**
309 * Sets the JNDI name to which the mail Session should be bound
310 * @param jndiName the JNDI name to which the mail Session should be bound
311 */
312 public void setJndiName(String jndiName) {
313 this.jndiName = jndiName;
314 }
315
316 public Object $getResource() {
317 Properties props = new Properties(properties);
318
319 if (protocols != null) {
320 for (Iterator iter = protocols.iterator(); iter.hasNext();) {
321 ProtocolGBean protocol = (ProtocolGBean) iter.next();
322 protocol.addOverrides(props);
323 }
324 }
325
326 props.putAll(properties);
327
328 if (storeProtocol != null) props.put("mail.store.protocol", storeProtocol);
329 if (transportProtocol != null) props.put("mail.transport.protocol", transportProtocol);
330 if (host != null) props.put("mail.host", host);
331 if (user != null) props.put("mail.user", user);
332 // this needs to be translated into a string version.
333 if (debug != null) props.put("mail.debug", debug.toString());
334
335 if (Boolean.TRUE.equals(useDefault)) {
336 if (authenticator == null) {
337 return Session.getDefaultInstance(props);
338 } else {
339 return Session.getDefaultInstance(props, authenticator);
340 }
341 } else {
342 if (authenticator == null) {
343 return Session.getInstance(props);
344 } else {
345 return Session.getInstance(props, authenticator);
346 }
347 }
348 }
349
350 public void doStart() throws Exception {
351 log.debug("Started " + objectName + " - will return "
352 + (Boolean.TRUE.equals(useDefault) ? "default" : "new")
353 + " JavaMail Session "
354 + (authenticator == null ? "without" : "with")
355 + " authenticator");
356
357 String jndiName = getJndiName();
358 if (jndiName != null && jndiName.length() > 0) {
359 // first get the resource incase there are exceptions
360 Object value = $getResource();
361
362 // get the initial context
363 Context context = new InitialContext();
364 Name parsedName = context.getNameParser("").parse(jndiName);
365
366 // create intermediate contexts
367 for (int i = 1; i < parsedName.size(); i++) {
368 Name contextName = parsedName.getPrefix(i);
369 if (!bindingExists(context, contextName)) {
370 context.createSubcontext(contextName);
371 }
372 }
373
374 // bind
375 context.bind(jndiName, value);
376 log.info("JavaMail session bound to " + jndiName);
377 }
378 }
379
380 public void doStop() throws Exception {
381 log.debug("Stopped " + objectName);
382 stop();
383 }
384
385 public void doFail() {
386 log.warn("Failed " + objectName);
387 stop();
388 }
389
390 private void stop() {
391 String jndiName = getJndiName();
392 if (jndiName != null && jndiName.length() > 0) {
393 try {
394 Context context = new InitialContext();
395 context.unbind(jndiName);
396 log.info("JavaMail session unbound from " + jndiName);
397 } catch (NamingException e) {
398 // we tried... this is a common error which occurs during shutdown due to ordering
399 }
400 }
401 }
402
403 private static boolean bindingExists(Context context, Name contextName) {
404 try {
405 return context.lookup(contextName) != null;
406 } catch (NamingException e) {
407 }
408 return false;
409 }
410
411 /**
412 * Returns the GBean name of this Mail GBean
413 */
414 public String getObjectName() {
415 return objectName;
416 }
417
418 public boolean isStateManageable() {
419 return false;
420 }
421
422 public boolean isStatisticsProvider() {
423 return false;
424 }
425
426 public boolean isEventProvider() {
427 return false;
428 }
429
430 public static final GBeanInfo GBEAN_INFO;
431
432 static {
433 GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(MailGBean.class, NameFactory.JAVA_MAIL_RESOURCE);
434
435 infoFactory.addAttribute("objectName", String.class, false);
436 infoFactory.addReference("Protocols", ProtocolGBean.class, NameFactory.GERONIMO_SERVICE);
437 infoFactory.addAttribute("useDefault", Boolean.class, true);
438 infoFactory.addAttribute("properties", Properties.class, true);
439 infoFactory.addReference("Authenticator", Authenticator.class, NameFactory.GERONIMO_SERVICE);
440 infoFactory.addAttribute("storeProtocol", String.class, true);
441 infoFactory.addAttribute("transportProtocol", String.class, true);
442 infoFactory.addAttribute("host", String.class, true);
443 infoFactory.addAttribute("user", String.class, true);
444 infoFactory.addAttribute("debug", Boolean.class, true);
445 infoFactory.addAttribute("jndiName", String.class, true);
446 infoFactory.addOperation("$getResource");
447 infoFactory.addOperation("getProtocols");
448 infoFactory.addInterface(JavaMailResource.class);
449
450 infoFactory.setConstructor(new String[]{"objectName",
451 "Protocols",
452 "useDefault",
453 "properties",
454 "Authenticator",
455 "storeProtocol",
456 "transportProtocol",
457 "host",
458 "user",
459 "debug",
460 "jndiName"});
461
462 GBEAN_INFO = infoFactory.getBeanInfo();
463 }
464
465 public static GBeanInfo getGBeanInfo() {
466 return GBEAN_INFO;
467 }
468 }