/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of the License at the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing permissions and * limitations under the License. */ package org.jasig.portlet.emailpreview.dao; import java.util.List; import javax.mail.Folder; import javax.portlet.PortletRequest; import net.sf.ehcache.Cache; import net.sf.ehcache.Element; import org.jasig.portlet.emailpreview.AccountSummary; import org.jasig.portlet.emailpreview.EmailMessage; import org.jasig.portlet.emailpreview.EmailPreviewException; import org.jasig.portlet.emailpreview.MailStoreConfiguration; import org.jasig.portlet.emailpreview.caching.AccountSummaryCacheKeyGeneratorImpl; import org.jasig.portlet.emailpreview.caching.IAccountSummaryCacheKeyGenerator; import org.jasig.portlet.emailpreview.caching.IMailAccountCacheKeyGenerator; import org.jasig.portlet.emailpreview.caching.MailAccountCacheKeyGeneratorImpl; import org.jasig.portlet.emailpreview.service.ICredentialsProvider; import org.jasig.portlet.emailpreview.service.IServiceBroker; import org.jasig.portlet.emailpreview.service.auth.IAuthenticationService; import org.jasig.portlet.emailpreview.service.auth.IAuthenticationServiceRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Required; /** * Implements the email account service, handling caching of data for efficiency. * * @author James Wennmacher, jwennmacher@unicon.net */ public class EmailAccountService implements IEmailAccountService { protected final Logger log = LoggerFactory.getLogger(getClass()); @Autowired(required = true) private IAuthenticationServiceRegistry authServiceRegistry; @Autowired(required = true) @Qualifier("simpleServiceBroker") private IServiceBroker serviceBroker; private IMailAccountDao dao; @Autowired private ICredentialsProvider credentialsService; @Autowired @Qualifier("inboxCache") private Cache inboxCache; private IAccountSummaryCacheKeyGenerator accountSummaryCacheKeyGenerator = new AccountSummaryCacheKeyGeneratorImpl(); @Autowired @Qualifier("exchangeFolderCache") private Cache folderCache; private IMailAccountCacheKeyGenerator folderCacheKeyGenerator = new MailAccountCacheKeyGeneratorImpl(); private String folderCacheKeyPrefix = "MailFolders"; public void setInboxCache(Cache inboxCache) { this.inboxCache = inboxCache; } public void setAccountSummaryCacheKeyGenerator( IAccountSummaryCacheKeyGenerator accountSummaryCacheKeyGenerator) { this.accountSummaryCacheKeyGenerator = accountSummaryCacheKeyGenerator; } public void setFolderCache(Cache folderCache) { this.folderCache = folderCache; } public void setFolderCacheKeyGenerator(IMailAccountCacheKeyGenerator folderCacheKeyGenerator) { this.folderCacheKeyGenerator = folderCacheKeyGenerator; } public void setFolderCacheKeyPrefix(String folderCacheKeyPrefix) { this.folderCacheKeyPrefix = folderCacheKeyPrefix; } @Required public void setDao(IMailAccountDao dao) { this.dao = dao; } public void setCredentialsService(ICredentialsProvider credentialsService) { this.credentialsService = credentialsService; } @Override public AccountSummary getAccountSummary( PortletRequest req, int start, int max, boolean refresh, String folder) { String username = req.getRemoteUser(); if (username == null) { throw new EmailPreviewException("Anonymous access is not supported"); } MailStoreConfiguration config = initializeEnvironment(req); config.setInboxFolderName(folder); String mailAccount = config.getMailAccount(); String key = accountSummaryCacheKeyGenerator.getKey( credentialsService.getUsername(), mailAccount, folder, config.getProtocol()); if (!refresh) { Element element = inboxCache.get(key); if (element != null) { AccountSummary summary = (AccountSummary) element.getObjectValue(); // If user has changed their starting index or max # of messages to return, need to refresh if (summary.getMessagesStart() == start && summary.getMessagesMax() == max) { log.debug( "Returning cached AccountSummary for [username={}, mailAccount={}, folder={}, start={}, max={}]", username, mailAccount, folder, start, max); return summary; } log.debug( "Different min or max than cached data so fetching data for username={}, mailAccount={}", username, mailAccount); } } log.debug( "Creating new AccountSummary for [username={}, mailAccount={}, folder={}, start={}, max={}]", username, mailAccount, folder, start, max); AccountSummary summary = dao.fetchAccountSummaryFromStore(config, username, mailAccount, folder, start, max); Element element = new Element(key, summary); inboxCache.put(element); return summary; } private void populateCredentials(PortletRequest req, MailStoreConfiguration config) { IAuthenticationService authService = authServiceRegistry.getAuthenticationService(config.getAuthenticationServiceKey()); credentialsService.initialize(req, config, authService); } private MailStoreConfiguration setupMailStoreConfig(PortletRequest req) { MailStoreConfiguration config = serviceBroker.getConfiguration(req); IAuthenticationService authService = authServiceRegistry.getAuthenticationService(config.getAuthenticationServiceKey()); if (authService == null) { String msg = "Unrecognized authentication service: " + config.getAuthenticationServiceKey(); log.error(msg); throw new EmailPreviewException(msg); } String mailAccount = authService.getMailAccountName(req, config); config.setMailAccount(mailAccount); return config; } private MailStoreConfiguration initializeEnvironment(PortletRequest req) { MailStoreConfiguration config = setupMailStoreConfig(req); populateCredentials(req, config); return config; } private void clearInboxCache(MailStoreConfiguration config) { String key = accountSummaryCacheKeyGenerator.getKey( credentialsService.getUsername(), config.getMailAccount(), config.getInboxFolderName(), config.getProtocol()); inboxCache.remove(key); } @Override public EmailMessage getMessage(PortletRequest req, String messageId) { MailStoreConfiguration config = initializeEnvironment(req); if (config.getMarkMessagesAsRead()) { log.debug("Getting message - marking message as read (may already be marked as read"); setSeenFlag(req, new String[] {messageId}, true); // Account summary is now invalid so clear it clearInboxCache(config); } log.debug("Getting message id={}", messageId); return dao.getMessage(config, messageId); } @Override public boolean deleteMessages(PortletRequest req, String[] messageIds) { MailStoreConfiguration config = initializeEnvironment(req); if (log.isDebugEnabled()) { log.debug("Deleting messages {}", convertIdsToString(messageIds)); } boolean wasDeleted = dao.deleteMessages(config, messageIds); // Account summary is now invalid so clear it clearInboxCache(config); return wasDeleted; } private String convertIdsToString(String[] messageIds) { StringBuffer ids = new StringBuffer(); for (String id : messageIds) { ids.append(id).append(","); } ids.deleteCharAt(ids.length() - 1); return ids.toString(); } @Override public boolean setSeenFlag(PortletRequest req, String[] messageIds, boolean read) { MailStoreConfiguration config = initializeEnvironment(req); boolean result = dao.setMessageReadStatus(config, messageIds, read); // Account summary is now invalid so clear it clearInboxCache(config); return result; } @Override public List<Folder> getAllUserInboxFolders(PortletRequest req) { MailStoreConfiguration config = setupMailStoreConfig(req); populateCredentials(req, config); // Retrieve from cache or fetch String key = folderCacheKeyGenerator.getKey( credentialsService.getUsername(), config.getMailAccount(), folderCacheKeyPrefix); Element element = folderCache.get(key); if (element != null) { log.debug( "Returning folder list from cache for user {} mail account {}", credentialsService.getUsername(), config.getMailAccount()); return (List<Folder>) element.getObjectValue(); } else { log.debug("Fetching all folders"); List<Folder> folders = dao.getAllUserInboxFolders(config); folderCache.put(new Element(key, folders)); return folders; } } }