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