1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.mail.internal

File DatabaseMailListener.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

12
64
13
1
247
176
23
0.36
4.92
13
1.77

Classes

Class Line # Actions
DatabaseMailListener 54 64 0% 23 10
0.887640588.8%
 

Contributing tests

This file is covered by 8 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.mail.internal;
21   
22    import java.util.Map;
23   
24    import javax.inject.Inject;
25    import javax.inject.Named;
26   
27    import org.apache.commons.lang3.exception.ExceptionUtils;
28    import org.xwiki.component.annotation.Component;
29    import org.xwiki.component.annotation.InstantiationStrategy;
30    import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
31    import org.xwiki.component.phase.Initializable;
32    import org.xwiki.component.phase.InitializationException;
33    import org.xwiki.context.Execution;
34    import org.xwiki.mail.ExtendedMimeMessage;
35    import org.xwiki.mail.MailContentStore;
36    import org.xwiki.mail.MailState;
37    import org.xwiki.mail.MailStatus;
38    import org.xwiki.mail.MailStatusResult;
39    import org.xwiki.mail.MailStatusStore;
40    import org.xwiki.mail.MailStorageConfiguration;
41    import org.xwiki.mail.MailStoreException;
42   
43    import com.xpn.xwiki.XWikiContext;
44   
45    /**
46    * Saves mail statuses in the database.
47    *
48    * @version $Id: 9aeb64203cf10d9d3d8fdd80cda303b91b67a2c9 $
49    * @since 6.4M3
50    */
51    @Component
52    @Named("database")
53    @InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
 
54    public class DatabaseMailListener extends AbstractMailListener implements Initializable
55    {
56    @Inject
57    private Execution execution;
58   
59    @Inject
60    @Named("filesystem")
61    private MailContentStore mailContentStore;
62   
63    @Inject
64    @Named("database")
65    private MailStatusStore mailStatusStore;
66   
67    @Inject
68    private MailStorageConfiguration configuration;
69   
70    private DatabaseMailStatusResult mailStatusResult;
71   
 
72  42 toggle @Override
73    public void initialize() throws InitializationException
74    {
75  42 mailStatusResult = new DatabaseMailStatusResult(this.mailStatusStore);
76    }
77   
 
78  42 toggle @Override
79    public void onPrepareBegin(String batchId, Map<String, Object> parameters)
80    {
81  42 super.onPrepareBegin(batchId, parameters);
82  42 mailStatusResult.setBatchId(batchId);
83    }
84   
 
85  9 toggle @Override
86    public void onPrepareMessageSuccess(ExtendedMimeMessage message, Map<String, Object> parameters)
87    {
88  9 super.onPrepareMessageSuccess(message, parameters);
89   
90  9 MailStatus status = new MailStatus(getBatchId(), message, MailState.PREPARE_SUCCESS);
91  9 status.setWiki(
92    ((XWikiContext) execution.getContext().getProperty(XWikiContext.EXECUTIONCONTEXT_KEY)).getWikiId());
93  9 saveStatus(status, parameters);
94    }
95   
 
96  1 toggle @Override
97    public void onPrepareMessageError(ExtendedMimeMessage message, Exception exception, Map<String, Object> parameters)
98    {
99  1 super.onPrepareMessageError(message, exception, parameters);
100   
101  1 MailStatus status = new MailStatus(getBatchId(), message, MailState.PREPARE_ERROR);
102  1 status.setWiki(
103    ((XWikiContext) execution.getContext().getProperty(XWikiContext.EXECUTIONCONTEXT_KEY)).getWikiId());
104  1 status.setError(exception);
105  1 saveStatus(status, parameters);
106   
107    // This mail will not reach the send queue, so its processing is done now.
108  1 mailStatusResult.incrementCurrentSize();
109    }
110   
 
111  0 toggle @Override
112    public void onPrepareFatalError(Exception exception, Map<String, Object> parameters)
113    {
114  0 super.onPrepareFatalError(exception, parameters);
115   
116    //TODO: Store failure exception
117  0 logger.error("Failure during preparation phase of thread [" + getBatchId() + "]", exception);
118    }
119   
 
120  9 toggle @Override
121    public void onSendMessageSuccess(ExtendedMimeMessage message, Map<String, Object> parameters)
122    {
123  9 super.onSendMessageSuccess(message, parameters);
124   
125  9 String uniqueMessageId = message.getUniqueMessageId();
126  9 MailStatus status = retrieveExistingMailStatus(uniqueMessageId, MailState.SEND_SUCCESS);
127   
128  9 if (status != null) {
129  6 status.setState(MailState.SEND_SUCCESS);
130    } else {
131  3 this.logger.warn("Forcing a new mail status for message [{}] of batch [{}] to send_success state.",
132    uniqueMessageId, getBatchId());
133  3 status = new MailStatus(getBatchId(), message, MailState.SEND_SUCCESS);
134    }
135   
136    // Since the mail was sent successfully we don't need to keep its serialized content
137  9 deleteMailContent(status);
138   
139    // If the user doesn't want to keep success status, we remove the mail status, otherwise we just update it
140  9 if (configuration.discardSuccessStatuses()) {
141  3 deleteStatus(status, parameters);
142    } else {
143  6 saveStatus(status, parameters);
144    }
145   
146  9 mailStatusResult.incrementCurrentSize();
147    }
148   
 
149  1 toggle @Override
150    public void onSendMessageFatalError(String uniqueMessageId, Exception exception, Map<String, Object> parameters)
151    {
152  1 super.onSendMessageFatalError(uniqueMessageId, exception, parameters);
153   
154  1 MailStatus status = retrieveExistingMailStatus(uniqueMessageId, MailState.SEND_FATAL_ERROR);
155   
156  1 if (status != null) {
157  1 status.setState(MailState.SEND_FATAL_ERROR);
158  1 status.setError(exception);
159  1 saveStatus(status, parameters);
160    } else {
161  0 this.logger.error("Unable to report the fatal error encountered during mail sending for message [{}] "
162    + "of batch [{}].", uniqueMessageId, getBatchId(), exception);
163    }
164   
165  1 this.mailStatusResult.incrementCurrentSize();
166    }
167   
 
168  2 toggle @Override
169    public void onSendMessageError(ExtendedMimeMessage message, Exception exception, Map<String, Object> parameters)
170    {
171  2 super.onSendMessageError(message, exception, parameters);
172   
173  2 String uniqueMessageId = message.getUniqueMessageId();
174  2 MailStatus status = retrieveExistingMailStatus(uniqueMessageId, MailState.SEND_ERROR);
175   
176  2 if (status != null) {
177  2 status.setState(MailState.SEND_ERROR);
178    } else {
179  0 this.logger.warn("Forcing a new mail status for message [{}] of batch [{}] to send_error state.",
180    uniqueMessageId, getBatchId());
181  0 status = new MailStatus(getBatchId(), message, MailState.SEND_ERROR);
182    }
183  2 status.setError(exception);
184  2 saveStatus(status, parameters);
185   
186  2 this.mailStatusResult.incrementCurrentSize();
187    }
188   
 
189  12 toggle private MailStatus retrieveExistingMailStatus(String uniqueMessageId, MailState state)
190    {
191  12 MailStatus status;
192  12 try {
193  12 status = mailStatusStore.load(uniqueMessageId);
194  11 if (status == null) {
195    // It's not normal to have no status in the mail status store since onPrepare should have been called
196    // before.
197  2 this.logger.error("Failed to find a previous mail status for message [{}] of batch [{}].",
198    uniqueMessageId, getBatchId(), state);
199    }
200    } catch (MailStoreException e) {
201  1 this.logger.error("Error when looking for a previous mail status for message [{}] of batch [{}].",
202    uniqueMessageId, getBatchId(), state, e);
203  1 status = null;
204    }
205  12 return status;
206    }
207   
 
208  38 toggle @Override
209    public MailStatusResult getMailStatusResult()
210    {
211  38 return mailStatusResult;
212    }
213   
 
214  19 toggle private void saveStatus(MailStatus status, Map<String, Object> parameters)
215    {
216  19 try {
217  19 mailStatusStore.save(status, parameters);
218    } catch (MailStoreException e) {
219    // Failed to save the status in the DB, we continue but log an error
220  1 logger.error("Failed to save mail status [{}] to the database", status, e);
221    }
222    }
223   
 
224  3 toggle private void deleteStatus(MailStatus status, Map<String, Object> parameters)
225    {
226  3 try {
227  3 mailStatusStore.delete(status.getMessageId(), parameters);
228    } catch (MailStoreException e) {
229    // Failed to delete the status in the DB, we continue but log an error
230  0 logger.error("Failed to delete mail status [{}] from the database", status, e);
231    }
232    }
233   
 
234  9 toggle private void deleteMailContent(MailStatus currentStatus)
235    {
236  9 if (currentStatus != null) {
237  9 try {
238  9 mailContentStore.delete(currentStatus.getBatchId(), currentStatus.getMessageId());
239    } catch (MailStoreException e) {
240    // Failed to delete saved mail, raise a warning but continue since it's not critical
241  1 this.logger.warn("Failed to remove previously failing message [{}] (batch id [{}]) from the file "
242    + "system. Reason [{}].", currentStatus.getMessageId(), currentStatus.getBatchId(),
243    ExceptionUtils.getRootCauseMessage(e));
244    }
245    }
246    }
247    }