001/* 002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Alexandre Russel 016 * 017 * $Id$ 018 */ 019 020package org.nuxeo.ecm.platform.mail.service; 021 022import java.util.HashMap; 023import java.util.Map; 024import java.util.Properties; 025 026import javax.mail.Address; 027import javax.mail.Folder; 028import javax.mail.Message; 029import javax.mail.MessagingException; 030import javax.mail.Session; 031import javax.mail.Store; 032import javax.mail.Transport; 033import javax.mail.internet.MimeMessage; 034 035import org.nuxeo.ecm.platform.ec.notification.email.EmailHelper; 036import org.nuxeo.ecm.platform.mail.action.MailBoxActions; 037import org.nuxeo.ecm.platform.mail.action.MailBoxActionsImpl; 038import org.nuxeo.ecm.platform.mail.action.MessageActionPipe; 039import org.nuxeo.ecm.platform.mail.action.MessageActionPipeDescriptor; 040import org.nuxeo.ecm.platform.mail.fetcher.PropertiesFetcher; 041import org.nuxeo.ecm.platform.mail.fetcher.PropertiesFetcherDescriptor; 042import org.nuxeo.runtime.api.Framework; 043import org.nuxeo.runtime.model.ComponentInstance; 044import org.nuxeo.runtime.model.DefaultComponent; 045 046/** 047 * @author Alexandre Russel 048 */ 049public class MailServiceImpl extends DefaultComponent implements MailService { 050 051 private static final String SESSION_FACTORY = "sessionFactory"; 052 053 private static final String PROPERTIES_FETCHER = "propertiesFetcher"; 054 055 private static final String ACTION_PIPES = "actionPipes"; 056 057 private final Map</* fetcher name */String, Class<? extends PropertiesFetcher>> fetchers = new HashMap<String, Class<? extends PropertiesFetcher>>(); 058 059 private final Map</* session factory name */String, SessionFactoryDescriptor> sessionFactories = new HashMap<String, SessionFactoryDescriptor>(); 060 061 private final Map</* session factory name */String, PropertiesFetcher> configuredFetchers = new HashMap<String, PropertiesFetcher>(); 062 063 private final Map<String, MessageActionPipe> actionPipesRegistry = new HashMap<String, MessageActionPipe>(); 064 065 private final Map<String, MessageActionPipeDescriptor> actionPipeDescriptorsRegistry = new HashMap<String, MessageActionPipeDescriptor>(); 066 067 static { 068 setDecodeUTFFileNamesSystemProperty(); 069 } 070 071 @Override 072 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 073 if (extensionPoint.equals(SESSION_FACTORY)) { 074 SessionFactoryDescriptor descriptor = (SessionFactoryDescriptor) contribution; 075 registerSessionFactory(descriptor); 076 } else if (extensionPoint.equals(PROPERTIES_FETCHER)) { 077 PropertiesFetcherDescriptor descriptor = (PropertiesFetcherDescriptor) contribution; 078 fetchers.put(descriptor.getName(), descriptor.getFetcher()); 079 } else if (extensionPoint.equals(ACTION_PIPES)) { 080 MessageActionPipeDescriptor descriptor = (MessageActionPipeDescriptor) contribution; 081 registerActionPipe(descriptor); 082 } 083 } 084 085 @Override 086 public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 087 // TODO deal with other extension points 088 if (extensionPoint.equals(ACTION_PIPES)) { 089 MessageActionPipeDescriptor descriptor = (MessageActionPipeDescriptor) contribution; 090 actionPipesRegistry.remove(descriptor.getName()); 091 } 092 } 093 094 private void registerSessionFactory(SessionFactoryDescriptor descriptor) { 095 sessionFactories.put(descriptor.getName(), descriptor); 096 } 097 098 private void registerActionPipe(MessageActionPipeDescriptor descriptor) { 099 if (!descriptor.getOverride()) { 100 MessageActionPipeDescriptor existingDescriptor = actionPipeDescriptorsRegistry.get(descriptor.getName()); 101 if (existingDescriptor != null) { 102 descriptor.merge(existingDescriptor); 103 } 104 } 105 actionPipeDescriptorsRegistry.put(descriptor.getName(), descriptor); 106 actionPipesRegistry.put(descriptor.getName(), descriptor.getPipe()); 107 } 108 109 private static void setDecodeUTFFileNamesSystemProperty() { 110 String toDecodeTheFilenames = Framework.getRuntime().getProperty("mail.mime.decodefilename"); 111 if (toDecodeTheFilenames == null) { 112 return; 113 } 114 toDecodeTheFilenames = toDecodeTheFilenames.trim().toLowerCase(); 115 if (toDecodeTheFilenames.equals("true") || toDecodeTheFilenames.equals("yes")) { 116 System.setProperty("mail.mime.decodefilename", "true"); 117 return; 118 } 119 System.setProperty("mail.mime.decodefilename", "false"); 120 } 121 122 public Store getConnectedStore(String name) throws MessagingException { 123 return getConnectedStore(name, null); 124 } 125 126 public Store getConnectedStore(String name, Map<String, Object> context) throws MessagingException { 127 Properties props = getProperties(name, context); 128 Session session = newSession(props); 129 Store store = session.getStore(); 130 store.connect(props.getProperty("user"), props.getProperty("password")); 131 return store; 132 } 133 134 private Properties getProperties(String name, Map<String, Object> map) { 135 return getFetcher(name).getProperties(map); 136 } 137 138 public Transport getConnectedTransport(String name) throws MessagingException { 139 return getConnectedTransport(name, null); 140 } 141 142 public Transport getConnectedTransport(String name, Map<String, Object> context) throws MessagingException { 143 Properties props = getProperties(name, context); 144 Session session = newSession(props); 145 Transport transport = session.getTransport(); 146 transport.connect(props.getProperty("user"), props.getProperty("password")); 147 return transport; 148 } 149 150 public Session getSession(String name) { 151 return getSession(name, null); 152 } 153 154 public Session getSession(String name, Map<String, Object> context) { 155 Properties props = getProperties(name, context); 156 return newSession(props); 157 } 158 159 public MailBoxActions getMailBoxActions(String factoryName, String folderName) throws MessagingException { 160 return getMailBoxActions(factoryName, folderName, null); 161 } 162 163 public MailBoxActions getMailBoxActions(String factoryName, String folderName, Map<String, Object> context) 164 throws MessagingException { 165 Store store = getConnectedStore(factoryName, context); 166 Folder folder = store.getFolder(folderName); 167 return new MailBoxActionsImpl(folder, true); 168 } 169 170 public void sendMail(String text, String subject, String factory, Address[] recipients) { 171 sendMail(text, subject, factory, recipients, null); 172 } 173 174 public void sendMail(String text, String subject, String factory, Address[] recipients, Map<String, Object> context) { 175 Session session = getSession(factory, context); 176 Message message = new MimeMessage(session); 177 try { 178 message.setFrom(); 179 message.setSubject(subject); 180 message.setRecipients(Message.RecipientType.TO, recipients); 181 message.setText(text); 182 Transport.send(message); 183 } catch (MessagingException e) { 184 throw new RuntimeException(e); 185 } 186 } 187 188 public PropertiesFetcher getFetcher(String name) { 189 PropertiesFetcher fetcher = configuredFetchers.get(name); 190 if (fetcher == null) { 191 String fetcherName = sessionFactories.get(name).getFetcherName(); 192 Class<? extends PropertiesFetcher> clazz = fetchers.get(fetcherName); 193 SessionFactoryDescriptor descriptor = sessionFactories.get(name); 194 try { 195 fetcher = clazz.newInstance(); 196 } catch (ReflectiveOperationException e) { 197 throw new RuntimeException(e); 198 } 199 fetcher.configureFetcher(descriptor.getProperties()); 200 configuredFetchers.put(name, fetcher); 201 } 202 return fetcher; 203 } 204 205 public MessageActionPipe getPipe(String name) { 206 return actionPipesRegistry.get(name); 207 } 208 209 protected Session newSession(Properties props) { 210 return EmailHelper.newSession(props); 211 } 212}