/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.mail; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import java.util.Properties; import javax.management.ObjectName; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.naming.InitialContext; import javax.naming.Reference; import javax.naming.StringRefAddr; import javax.naming.NamingException; import javax.mail.Session; import javax.mail.PasswordAuthentication; import javax.mail.Authenticator; import org.jboss.system.ServiceMBeanSupport; import org.jboss.naming.NonSerializableFactory; import org.jboss.util.naming.Util; /** * MBean that gives support for JavaMail. Object of class javax.mail.Session will be bound * in JNDI with the name provided with method {@link #setJNDIName}. * * @jmx:mbean name="jboss:type=Service,service=Mail" * extends="org.jboss.system.ServiceMBean" * * @version <tt>$Revision: 81038 $</tt> * @author <a href="mailto:simone.bordet@compaq.com">Simone Bordet</a> * @author <a href="mailto:jason@planet57.com">Jason Dillon</a> * @author Scott.Stark@jboss.org */ public class MailService extends ServiceMBeanSupport implements MailServiceMBean { public static final String JNDI_NAME = "java:/Mail"; /** */ private String user; /** */ private String password; /** */ private String jndiName = JNDI_NAME; /** Whether lookups share a single session */ private boolean sharedSession = false; private Element config; /** Object Name of the JSR-77 representation of this service */ ObjectName mMail; /** save properties here */ Properties ourProps = null; /** * User id used to connect to a mail server * * @see #setPassword * * @jmx:managed-attribute */ public void setUser(final String user) { this.user = user; } /** * @jmx:managed-attribute */ public String getUser() { return user; } /** * Password used to connect to a mail server * * @see #setUser * * @jmx:managed-attribute */ public void setPassword(final String password) { this.password = password; } /** * Password is write only. */ protected String getPassword() { return password; } /** * Configuration for the mail service. * * @jmx:managed-attribute */ public Element getConfiguration() { return config; } /** * Configuration for the mail service. * * @jmx:managed-attribute */ public void setConfiguration(final Element element) { config = element; } /** The JNDI name under which javax.mail.Session objects are bound. * * @jmx:managed-attribute */ public void setJNDIName(final String name) { jndiName = name; } /** * @jmx:managed-attribute */ public String getJNDIName() { return jndiName; } public boolean isSharedSession() { return sharedSession; } /** * Set whether a single mail session should be shared across all lookups * (sharedSession = true) or a new session created on each lookup * (sharedSession = false, the default). * @param sharedSession */ public void setSharedSession(boolean sharedSession) { this.sharedSession = sharedSession; } /** * @jmx:managed-attribute */ public String getStoreProtocol() { if (ourProps != null) return ourProps.getProperty("mail.store.protocol"); else return null; } /** * @jmx:managed-attribute */ public String getTransportProtocol() { if (ourProps != null) return ourProps.getProperty("mail.transport.protocol"); else return null; } /** * @jmx:managed-attribute */ public String getDefaultSender() { if (ourProps != null) return ourProps.getProperty("mail.from"); else return null; } /** * @jmx:managed-attribute */ public String getSMTPServerHost() { if (ourProps != null) return ourProps.getProperty("mail.smtp.host"); else return null; } /** * @jmx:managed-attribute */ public String getPOP3ServerHost() { if (ourProps != null) return ourProps.getProperty("mail.pop3.host"); else return null; } protected ObjectName getObjectName(MBeanServer server, ObjectName name) throws MalformedObjectNameException { return name == null ? OBJECT_NAME : name; } protected void startService() throws Exception { // Setup password authentication final PasswordAuthentication pa = new PasswordAuthentication(getUser(), getPassword()); Authenticator a = new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return pa; } }; Properties props = getProperties(); // Finally bind a mail session bind(props, a); // now make the properties available ourProps = props; } protected Properties getProperties() throws Exception { Properties props = new Properties(); if (config == null) { log.warn("No configuration specified; using empty properties map"); return props; } NodeList list = config.getElementsByTagName("property"); int len = list.getLength(); for (int i = 0; i < len; i++) { Node node = list.item(i); switch (node.getNodeType()) { case Node.ELEMENT_NODE: Element child = (Element) node; String name, value; // get the name if (child.hasAttribute("name")) { name = child.getAttribute("name"); } else { log.warn("Ignoring invalid element; missing 'name' attribute: " + child); break; } // get the value if (child.hasAttribute("value")) { value = child.getAttribute("value"); } else { log.warn("Ignoring invalid element; missing 'value' attribute: " + child); break; } if (log.isTraceEnabled()) { log.trace("setting property " + name + "=" + value); } props.setProperty(name, value); break; case Node.COMMENT_NODE: // ignore break; default: log.debug("ignoring unsupported node type: " + node); break; } } log.debug("Using properties: " + props); return props; } protected void stopService() throws Exception { unbind(); } private void bind(Properties props, Authenticator auth) throws NamingException { String bindName = getJNDIName(); SessionObjectFactory.setSessionFactoryInfo(props, auth); SessionObjectFactory.setShareSessionInstance(sharedSession); InitialContext ctx = new InitialContext(); try { StringRefAddr addr = new StringRefAddr("nns", bindName); Reference ref = new Reference(Session.class.getName(), addr, SessionObjectFactory.class.getName(), null); Util.bind(ctx, bindName, ref); } finally { ctx.close(); } log.info("Mail Service bound to " + bindName); } private void unbind() throws NamingException { String bindName = getJNDIName(); if (bindName != null) { InitialContext ctx = new InitialContext(); try { ctx.unbind(bindName); } finally { ctx.close(); } SessionObjectFactory.setSessionFactoryInfo(null, null); log.info("Mail service '" + getJNDIName() + "' removed from JNDI"); } } }