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