001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mail;
023:
024: import org.w3c.dom.Element;
025: import org.w3c.dom.Node;
026: import org.w3c.dom.NodeList;
027:
028: import java.util.Properties;
029:
030: import javax.management.ObjectName;
031: import javax.management.MBeanServer;
032: import javax.management.MalformedObjectNameException;
033:
034: import javax.naming.InitialContext;
035: import javax.naming.Reference;
036: import javax.naming.StringRefAddr;
037: import javax.naming.Name;
038: import javax.naming.Context;
039: import javax.naming.NamingException;
040: import javax.naming.NameNotFoundException;
041:
042: import javax.mail.Session;
043: import javax.mail.PasswordAuthentication;
044: import javax.mail.Authenticator;
045:
046: import org.jboss.system.ServiceMBeanSupport;
047: import org.jboss.naming.NonSerializableFactory;
048:
049: /**
050: * MBean that gives support for JavaMail. Object of class javax.mail.Session will be bound
051: * in JNDI with the name provided with method {@link #setJNDIName}.
052: *
053: * @jmx:mbean name="jboss:type=Service,service=Mail"
054: * extends="org.jboss.system.ServiceMBean"
055: *
056: * @version <tt>$Revision: 57210 $</tt>
057: * @author <a href="mailto:simone.bordet@compaq.com">Simone Bordet</a>
058: * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
059: * @author Scott.Stark@jboss.org
060: */
061: public class MailService extends ServiceMBeanSupport implements
062: MailServiceMBean {
063: public static final String JNDI_NAME = "java:/Mail";
064:
065: private String user;
066: private String password;
067: private String jndiName = JNDI_NAME;
068: private Element config;
069:
070: /** Object Name of the JSR-77 representant of this service */
071: ObjectName mMail;
072:
073: /** save properties here */
074: Properties ourProps = null;
075:
076: /**
077: * User id used to connect to a mail server
078: *
079: * @see #setPassword
080: *
081: * @jmx:managed-attribute
082: */
083: public void setUser(final String user) {
084: this .user = user;
085: }
086:
087: /**
088: * @jmx:managed-attribute
089: */
090: public String getUser() {
091: return user;
092: }
093:
094: /**
095: * Password used to connect to a mail server
096: *
097: * @see #setUser
098: *
099: * @jmx:managed-attribute
100: */
101: public void setPassword(final String password) {
102: this .password = password;
103: }
104:
105: /**
106: * Password is write only.
107: */
108: protected String getPassword() {
109: return password;
110: }
111:
112: /**
113: * Configuration for the mail service.
114: *
115: * @jmx:managed-attribute
116: */
117: public Element getConfiguration() {
118: return config;
119: }
120:
121: /**
122: * Configuration for the mail service.
123: *
124: * @jmx:managed-attribute
125: */
126: public void setConfiguration(final Element element) {
127: config = element;
128: }
129:
130: /** The JNDI name under which javax.mail.Session objects are bound.
131: *
132: * @jmx:managed-attribute
133: */
134: public void setJNDIName(final String name) {
135: jndiName = name;
136: }
137:
138: /**
139: * @jmx:managed-attribute
140: */
141: public String getJNDIName() {
142: return jndiName;
143: }
144:
145: /**
146: * @jmx:managed-attribute
147: */
148: public String getStoreProtocol() {
149: if (ourProps != null)
150: return ourProps.getProperty("mail.store.protocol");
151: else
152: return null;
153: }
154:
155: /**
156: * @jmx:managed-attribute
157: */
158: public String getTransportProtocol() {
159: if (ourProps != null)
160: return ourProps.getProperty("mail.transport.protocol");
161: else
162: return null;
163: }
164:
165: /**
166: * @jmx:managed-attribute
167: */
168: public String getDefaultSender() {
169: if (ourProps != null)
170: return ourProps.getProperty("mail.from");
171: else
172: return null;
173: }
174:
175: /**
176: * @jmx:managed-attribute
177: */
178: public String getSMTPServerHost() {
179: if (ourProps != null)
180: return ourProps.getProperty("mail.smtp.host");
181: else
182: return null;
183: }
184:
185: /**
186: * @jmx:managed-attribute
187: */
188: public String getPOP3ServerHost() {
189: if (ourProps != null)
190: return ourProps.getProperty("mail.pop3.host");
191: else
192: return null;
193: }
194:
195: protected ObjectName getObjectName(MBeanServer server,
196: ObjectName name) throws MalformedObjectNameException {
197: return name == null ? OBJECT_NAME : name;
198: }
199:
200: protected void startService() throws Exception {
201: // Setup password authentication
202: final PasswordAuthentication pa = new PasswordAuthentication(
203: getUser(), getPassword());
204: Authenticator a = new Authenticator() {
205: protected PasswordAuthentication getPasswordAuthentication() {
206: return pa;
207: }
208: };
209:
210: Properties props = getProperties();
211:
212: // Finally create a mail session
213: Session session = Session.getInstance(props, a);
214: bind(session);
215:
216: // now make the properties available
217: ourProps = props;
218: }
219:
220: protected Properties getProperties() throws Exception {
221: boolean debug = log.isDebugEnabled();
222:
223: Properties props = new Properties();
224: if (config == null) {
225: log
226: .warn("No configuration specified; using empty properties map");
227: return props;
228: }
229:
230: NodeList list = config.getElementsByTagName("property");
231: int len = list.getLength();
232:
233: for (int i = 0; i < len; i++) {
234: Node node = list.item(i);
235:
236: switch (node.getNodeType()) {
237: case Node.ELEMENT_NODE:
238: Element child = (Element) node;
239: String name,
240: value;
241:
242: // get the name
243: if (child.hasAttribute("name")) {
244: name = child.getAttribute("name");
245: } else {
246: log
247: .warn("Ignoring invalid element; missing 'name' attribute: "
248: + child);
249: break;
250: }
251:
252: // get the value
253: if (child.hasAttribute("value")) {
254: value = child.getAttribute("value");
255: } else {
256: log
257: .warn("Ignoring invalid element; missing 'value' attribute: "
258: + child);
259: break;
260: }
261:
262: if (debug) {
263: log.debug("setting property " + name + "=" + value);
264: }
265: props.setProperty(name, value);
266: break;
267:
268: case Node.COMMENT_NODE:
269: // ignore
270: break;
271:
272: default:
273: log.debug("ignoring unsupported node type: " + node);
274: break;
275: }
276: }
277:
278: if (debug) {
279: log.debug("Using properties: " + props);
280: }
281:
282: return props;
283: }
284:
285: protected void stopService() throws Exception {
286: unbind();
287: }
288:
289: private void bind(Session session) throws NamingException {
290: String bindName = getJNDIName();
291:
292: // Ah ! Session isn't serializable, so we use a helper class
293: NonSerializableFactory.bind(bindName, session);
294:
295: Context ctx = new InitialContext();
296: try {
297: Name n = ctx.getNameParser("").parse(bindName);
298: while (n.size() > 1) {
299: String ctxName = n.get(0);
300: try {
301: ctx = (Context) ctx.lookup(ctxName);
302: } catch (NameNotFoundException e) {
303: ctx = ctx.createSubcontext(ctxName);
304: }
305: n = n.getSuffix(1);
306: }
307:
308: // The helper class NonSerializableFactory uses address type nns, we go on to
309: // use the helper class to bind the javax.mail.Session object in JNDI
310:
311: StringRefAddr addr = new StringRefAddr("nns", bindName);
312: Reference ref = new Reference(Session.class.getName(),
313: addr, NonSerializableFactory.class.getName(), null);
314: ctx.bind(n.get(0), ref);
315: } finally {
316: ctx.close();
317: }
318:
319: log.info("Mail Service bound to " + bindName);
320: }
321:
322: private void unbind() throws NamingException {
323: String bindName = getJNDIName();
324:
325: if (bindName != null) {
326: InitialContext ctx = new InitialContext();
327: try {
328: ctx.unbind(bindName);
329: } finally {
330: ctx.close();
331: }
332:
333: NonSerializableFactory.unbind(bindName);
334: log.info("Mail service '" + getJNDIName()
335: + "' removed from JNDI");
336: }
337: }
338: }
|