/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* 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.xwiki.contrib.mailarchive.internal;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.MessagingException;
import org.codehaus.plexus.util.ExceptionUtils;
import org.slf4j.Logger;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.phase.Initializable;
import org.xwiki.component.phase.InitializationException;
import org.xwiki.contrib.mail.IMailComponent;
import org.xwiki.contrib.mail.IMailReader;
import org.xwiki.contrib.mailarchive.IMASource;
import org.xwiki.contrib.mailarchive.IMailArchive;
import org.xwiki.contrib.mailarchive.IMailArchiveConfiguration;
import org.xwiki.contrib.mailarchive.IMailArchiveLoader;
import org.xwiki.contrib.mailarchive.LoadingSession;
import org.xwiki.contrib.mailarchive.exceptions.MailArchiveException;
import org.xwiki.contrib.mailarchive.internal.data.MailStore;
import org.xwiki.contrib.mailarchive.internal.data.Server;
import org.xwiki.contrib.mailarchive.utils.IAggregatedLoggerManager;
import org.xwiki.logging.LogLevel;
import org.xwiki.rendering.parser.StreamParser;
/**
* @version $Id$
*/
@Component
@Singleton
public class DefaultMailLoader implements IMailArchiveLoader, Initializable
{
@Inject
private IMailArchive mailArchive;
/** Provides access to low-level mail api component */
@Inject
private IMailComponent mailManager;
/** Provides access to the Mail archive configuration */
@Inject
private IMailArchiveConfiguration config;
/** Aggregated component logger */
@Inject
private IAggregatedLoggerManager aggregatedLoggerManager;
@Inject
private Logger logger;
/**
* {@inheritDoc}
*
* @see org.xwiki.component.phase.Initializable#initialize()
*/
@Override
public void initialize() throws InitializationException
{
aggregatedLoggerManager.addComponentLogger(IMailArchive.class);
aggregatedLoggerManager.addComponentLogger(IMailComponent.class);
aggregatedLoggerManager.addComponentLogger(StreamParser.class);
}
/**
* @param session
* @return
*/
public int loadMails(final LoadingSession session)
{
return loadMails(session, null);
}
/**
* {@inheritDoc}
*
* @see org.xwiki.contrib.mailarchive.IMailArchive#loadMails(org.xwiki.contrib.mailarchive.LoadingSession)
*/
public int loadMails(final LoadingSession session, final LoadingJob job)
{
int nbSuccess = 0;
if (session == null) {
logger.warn("Invalid loading session (null) ...");
return -1;
} else {
logger.info("Starting new mail loading session...");
}
boolean hasLock = mailArchive.lock();
if (!hasLock) {
logger.warn("Loading process already in progress ...");
return -1;
}
logger.debug("Locked the archive");
try {
if (session.isDebugMode()) {
aggregatedLoggerManager.pushLogLevel(LogLevel.DEBUG);
} else {
aggregatedLoggerManager.pushLogLevel(LogLevel.INFO);
}
logger.debug("Loading parameters: " + session.toString());
// Reinitialize configuration
// FIXME: not very nice to call getConfiguration to reload configuration from db ...
this.config = mailArchive.getConfiguration();
final List<IMASource> servers = mailArchive.getSourcesList(session);
if (servers != null && !servers.isEmpty()) {
if (job != null) {
job.notifyPushLevelProgress(servers.size());
}
// Loop on all servers
for (IMASource server : servers) {
if (job != null) {
if (job.getStatus().isStopped())
break;
while (job.getStatus().isPaused()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
IMailReader mailReader = getReader(server);
if (job != null) {
job.getStatus().setCurrentSource("" + server.getType() + ':' + server.getId());
}
if (mailReader != null) {
nbSuccess += loadMails(mailReader, server.getFolder(), session, server.getId(), job);
mailReader.close();
}
if (job != null) {
job.notifyStepPropress();
}
}
if (job != null) {
job.notifyPopLevelProgress();
}
try {
// Compute timeline feed
if (config.isManageTimeline() && nbSuccess > 0) {
mailArchive.computeTimeline();
}
} catch (Exception e) {
logger.warn("Could not compute timeline data", e);
}
} else {
logger.warn("No Server nor Store found to load from, nothing to do");
}
} catch (InitializationException e) {
logger.error("Could not initialize a component", e);
nbSuccess = -1;
} catch (MailArchiveException e) {
logger.error("Could not retrieve configuration", e);
nbSuccess = -1;
} finally {
mailArchive.unlock();
aggregatedLoggerManager.popLogLevel();
}
return nbSuccess;
}
/**
* @param mailReader
* @param folder
* @param session
* @param serverId
* @param job
* @return
*/
protected int loadMails(IMailReader mailReader, final String folder, final LoadingSession session,
final String serverId, final LoadingJob job)
{
logger.debug("[{}] loadMails(mailReader={}, folder={}, session={}, serverId={}, job={}", serverId, mailReader,
folder, session, serverId, job);
int currentMsg = 1;
int nbSuccess = 0;
List<Message> messages = null;
if (mailReader != null) {
try {
messages = mailReader.read(folder, !session.isLoadAll(), session.getLimit());
} catch (MessagingException e) {
logger.warn("[{}] Can't read messages from server", serverId, e);
messages = new ArrayList<Message>();
}
}
final int total = messages.size();
int limit = session.getLimit();
if (limit > 0) {
if (limit > total) {
limit = total;
}
} else {
limit = total;
}
logger.info("[{}] Number of messages to treat : {} / {}", new Object[] {serverId, limit, total});
if (job != null) {
job.notifyPushLevelProgress(limit);
}
MailLoadingResult result = null;
while (currentMsg < limit && (job != null && !job.getStatus().isStopped())) {
logger.info("Current {} / limit {}", currentMsg, limit);
while (job != null && job.getStatus().isPaused()) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
Message message = messages.get(currentMsg - 1);
logger.debug("[{}] Loading message {}/{}", new Object[] {serverId, currentMsg, total});
try {
try {
if (session.isDebugMode()) {
mailArchive.dumpEmail(message);
}
if (job != null) {
job.getStatus().setCurrentMail(message.getSubject());
}
result = mailArchive.loadMail(message, !session.isSimulationMode(), false, null);
} catch (Exception me) {
if (me instanceof MessagingException || me instanceof IOException) {
logger.debug("[" + serverId + "] Could not load email because of", me);
logger.info("[{}] Could not load email {}, trying to load a clone", currentMsg, serverId);
message = mailReader.cloneEmail(message);
if (message != null) {
result = mailArchive.loadMail(message, !session.isSimulationMode(), false, null);
}
} else {
logger.warn("Unexpected exception occurred while loading email [{}]",
ExceptionUtils.getRootCause(me));
}
}
if (job != null) {
job.notifyStepPropress();
}
if (result != null) {
if (result.isSuccess()) {
nbSuccess++;
if (!session.isSimulationMode()) {
message.setFlag(Flags.Flag.SEEN, true);
// Back it up in the built-in store
if (config.isUseStore()) {
mailArchive.saveToInternalStore(serverId, mailReader.getMailSource(), message);
}
}
if (job != null) {
job.getStatus().incNbSuccess();
}
} else if (job != null) {
job.getStatus().incNbFailure();
}
if (job != null) {
if (MailLoadingResult.STATUS.ALREADY_LOADED.equals(result.getStatus())) {
job.getStatus().incNbAlreadyLoaded();
}
if (MailLoadingResult.STATUS.NOT_MATCHING_MAILING_LISTS.equals(result.getStatus())) {
job.getStatus().incNbNotMatchingMailingLists();
}
}
}
} catch (Throwable e) {
logger.error("[{}] Failed to load mail [{}]", serverId, ExceptionUtils.getRootCause(e));
}
currentMsg++;
}
if (job != null) {
job.getStatus().setCurrentMail("");
job.notifyPopLevelProgress();
}
return nbSuccess;
}
protected IMailReader getReader(final IMASource source)
{
if (!source.isEnabled()) {
logger.info("[{}] Server not enabled, skipping it", source.getId());
return null;
}
logger.info("[{}] Creating reader", source.getId());
IMailReader mailReader = null;
try {
if (source instanceof Server) {
Server s = (Server) source;
mailReader =
mailManager.getMailReader(s.getHostname(), s.getPort(), s.getProtocol(), s.getUsername(),
s.getPassword(), source.getAdditionalProperties(), s.isAutoTrustSSLCertificates());
} else if (source instanceof MailStore) {
MailStore s = (MailStore) source;
mailReader = mailManager.getStoreManager(s.getFormat(), s.getLocation());
}
} catch (Exception e1) {
logger.warn("[{}] Can't retrieve a mail reader", source.getId(), e1);
}
return mailReader;
}
}