001 /****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one *
003 * or more contributor license agreements. See the NOTICE file *
004 * distributed with this work for additional information *
005 * regarding copyright ownership. The ASF licenses this file *
006 * to you under the Apache License, Version 2.0 (the *
007 * "License"); you may not use this file except in compliance *
008 * with the License. You may obtain a copy of the License at *
009 * *
010 * http://www.apache.org/licenses/LICENSE-2.0 *
011 * *
012 * Unless required by applicable law or agreed to in writing, *
013 * software distributed under the License is distributed on an *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015 * KIND, either express or implied. See the License for the *
016 * specific language governing permissions and limitations *
017 * under the License. *
018 ****************************************************************/
019
020 package org.apache.james.fetchmail;
021
022 import java.util.ArrayList;
023 import java.util.Collections;
024 import java.util.Enumeration;
025 import java.util.HashMap;
026 import java.util.Iterator;
027 import java.util.List;
028 import java.util.Map;
029 import java.util.Properties;
030
031 import javax.mail.MessagingException;
032 import javax.mail.Session;
033
034 import org.apache.commons.configuration.Configuration;
035 import org.apache.commons.configuration.ConfigurationException;
036 import org.apache.commons.configuration.HierarchicalConfiguration;
037 import org.apache.commons.configuration.HierarchicalConfiguration.Node;
038 import org.apache.james.dnsservice.api.DNSService;
039 import org.apache.james.domainlist.api.DomainList;
040 import org.apache.james.lifecycle.api.Configurable;
041 import org.apache.james.lifecycle.api.LogEnabled;
042 import org.apache.james.queue.api.MailQueue;
043 import org.apache.james.user.api.UsersRepository;
044 import org.apache.james.user.api.UsersRepositoryException;
045 import org.slf4j.Logger;
046
047 /**
048 * <p>
049 * Class <code>FetchMail</code> is an Avalon task that is periodically triggered
050 * to fetch mail from a JavaMail Message Store.
051 * </p>
052 *
053 * <p>
054 * The lifecycle of an instance of <code>FetchMail</code> is managed by Avalon.
055 * The <code>configure(Configuration)</code> method is invoked to parse and
056 * validate Configuration properties. The targetTriggered(String) method is
057 * invoked to execute the task.
058 * </p>
059 *
060 * <p>
061 * When triggered, a sorted list of Message Store Accounts to be processed is
062 * built. Each Message Store Account is processed by delegating to
063 * <code>StoreProcessor</code>.
064 * </p>
065 *
066 * <p>
067 * There are two kinds of Message Store Accounts, static and dynamic. Static
068 * accounts are expliciltly declared in the Configuration. Dynamic accounts are
069 * built each time the task is executed, one per each user defined to James,
070 * using the James user name with a configurable prefix and suffix to define the
071 * host user identity and recipient identity for each Account. Dynamic accounts
072 * allow <code>FetchMail</code> to fetch mail for all James users without
073 * modifying the Configuration parameters or restarting the Avalon server.
074 * </p>
075 *
076 * <p>
077 * To fully understand the operations supported by this task, read the Class
078 * documention for each Class in the delegation chain starting with this class'
079 * delegate, <code>StoreProcessor</code>.
080 * </p>
081 */
082 public class FetchMail implements Runnable, LogEnabled, Configurable {
083 /**
084 * Key fields for DynamicAccounts.
085 */
086 private final static class DynamicAccountKey {
087 /**
088 * The base user name without prfix or suffix
089 */
090 private String fieldUserName;
091
092 /**
093 * The sequence number of the parameters used to construct the Account
094 */
095 private int fieldSequenceNumber;
096
097 /**
098 * Constructor for DynamicAccountKey.
099 */
100 private DynamicAccountKey() {
101 super();
102 }
103
104 /**
105 * Constructor for DynamicAccountKey.
106 */
107 public DynamicAccountKey(String userName, int sequenceNumber) {
108 this();
109 setUserName(userName);
110 setSequenceNumber(sequenceNumber);
111 }
112
113 /**
114 * @see java.lang.Object#equals(Object)
115 */
116 public boolean equals(Object obj) {
117 if (null == obj)
118 return false;
119 if (!(obj.getClass() == getClass()))
120 return false;
121 return (getUserName().equals(((DynamicAccountKey) obj).getUserName()) && getSequenceNumber() == ((DynamicAccountKey) obj).getSequenceNumber());
122 }
123
124 /**
125 * @see java.lang.Object#hashCode()
126 */
127 public int hashCode() {
128 return getUserName().hashCode() ^ getSequenceNumber();
129 }
130
131 /**
132 * Returns the sequenceNumber.
133 *
134 * @return int
135 */
136 public int getSequenceNumber() {
137 return fieldSequenceNumber;
138 }
139
140 /**
141 * Returns the userName.
142 *
143 * @return String
144 */
145 public String getUserName() {
146 return fieldUserName;
147 }
148
149 /**
150 * Sets the sequenceNumber.
151 *
152 * @param sequenceNumber
153 * The sequenceNumber to set
154 */
155 protected void setSequenceNumber(int sequenceNumber) {
156 fieldSequenceNumber = sequenceNumber;
157 }
158
159 /**
160 * Sets the userName.
161 *
162 * @param userName
163 * The userName to set
164 */
165 protected void setUserName(String userName) {
166 fieldUserName = userName;
167 }
168
169 }
170
171 private final static class ParsedDynamicAccountParameters {
172 private String fieldUserPrefix;
173 private String fieldUserSuffix;
174
175 private String fieldPassword;
176
177 private int fieldSequenceNumber;
178
179 private boolean fieldIgnoreRecipientHeader;
180 private String fieldRecipientPrefix;
181 private String fieldRecipientSuffix;
182 private String customRecipientHeader;
183
184 /**
185 * Constructor for ParsedDynamicAccountParameters.
186 */
187 private ParsedDynamicAccountParameters() {
188 super();
189 }
190
191 /**
192 * Constructor for ParsedDynamicAccountParameters.
193 */
194 public ParsedDynamicAccountParameters(int sequenceNumber, Configuration configuration) throws ConfigurationException {
195 this();
196 setSequenceNumber(sequenceNumber);
197 setUserPrefix(configuration.getString("[@userprefix]", ""));
198 setUserSuffix(configuration.getString("[@usersuffix]", ""));
199 setRecipientPrefix(configuration.getString("[@recipientprefix]", ""));
200 setRecipientSuffix(configuration.getString("[@recipientsuffix]", ""));
201 setPassword(configuration.getString("[@password]"));
202 setIgnoreRecipientHeader(configuration.getBoolean("[@ignorercpt-header]"));
203 setCustomRecipientHeader(configuration.getString("[@customrcpt-header]", ""));
204 }
205
206 /**
207 * Returns the custom recipient header.
208 *
209 * @return String
210 */
211 public String getCustomRecipientHeader() {
212 return this.customRecipientHeader;
213 }
214
215 /**
216 * Returns the recipientprefix.
217 *
218 * @return String
219 */
220 public String getRecipientPrefix() {
221 return fieldRecipientPrefix;
222 }
223
224 /**
225 * Returns the recipientsuffix.
226 *
227 * @return String
228 */
229 public String getRecipientSuffix() {
230 return fieldRecipientSuffix;
231 }
232
233 /**
234 * Returns the userprefix.
235 *
236 * @return String
237 */
238 public String getUserPrefix() {
239 return fieldUserPrefix;
240 }
241
242 /**
243 * Returns the userSuffix.
244 *
245 * @return String
246 */
247 public String getUserSuffix() {
248 return fieldUserSuffix;
249 }
250
251 /**
252 * Sets the custom recipient header.
253 *
254 * @param customRecipientHeader
255 * The header to be used
256 */
257 public void setCustomRecipientHeader(String customRecipientHeader) {
258 this.customRecipientHeader = customRecipientHeader;
259 }
260
261 /**
262 * Sets the recipientprefix.
263 *
264 * @param recipientprefix
265 * The recipientprefix to set
266 */
267 protected void setRecipientPrefix(String recipientprefix) {
268 fieldRecipientPrefix = recipientprefix;
269 }
270
271 /**
272 * Sets the recipientsuffix.
273 *
274 * @param recipientsuffix
275 * The recipientsuffix to set
276 */
277 protected void setRecipientSuffix(String recipientsuffix) {
278 fieldRecipientSuffix = recipientsuffix;
279 }
280
281 /**
282 * Sets the userprefix.
283 *
284 * @param userprefix
285 * The userprefix to set
286 */
287 protected void setUserPrefix(String userprefix) {
288 fieldUserPrefix = userprefix;
289 }
290
291 /**
292 * Sets the userSuffix.
293 *
294 * @param userSuffix
295 * The userSuffix to set
296 */
297 protected void setUserSuffix(String userSuffix) {
298 fieldUserSuffix = userSuffix;
299 }
300
301 /**
302 * Returns the password.
303 *
304 * @return String
305 */
306 public String getPassword() {
307 return fieldPassword;
308 }
309
310 /**
311 * Sets the ignoreRecipientHeader.
312 *
313 * @param ignoreRecipientHeader
314 * The ignoreRecipientHeader to set
315 */
316 protected void setIgnoreRecipientHeader(boolean ignoreRecipientHeader) {
317 fieldIgnoreRecipientHeader = ignoreRecipientHeader;
318 }
319
320 /**
321 * Sets the password.
322 *
323 * @param password
324 * The password to set
325 */
326 protected void setPassword(String password) {
327 fieldPassword = password;
328 }
329
330 /**
331 * Returns the ignoreRecipientHeader.
332 *
333 * @return boolean
334 */
335 public boolean isIgnoreRecipientHeader() {
336 return fieldIgnoreRecipientHeader;
337 }
338
339 /**
340 * Returns the sequenceNumber.
341 *
342 * @return int
343 */
344 public int getSequenceNumber() {
345 return fieldSequenceNumber;
346 }
347
348 /**
349 * Sets the sequenceNumber.
350 *
351 * @param sequenceNumber
352 * The sequenceNumber to set
353 */
354 protected void setSequenceNumber(int sequenceNumber) {
355 fieldSequenceNumber = sequenceNumber;
356 }
357
358 }
359
360 /**
361 * @see org.apache.avalon.cornerstone.services.scheduler.Target#targetTriggered(String)
362 */
363 private boolean fieldFetching = false;
364
365 /**
366 * The Configuration for this task
367 */
368 private ParsedConfiguration fieldConfiguration;
369
370 /**
371 * A List of ParsedDynamicAccountParameters, one for every <alllocal> entry
372 * in the configuration.
373 */
374 private List<ParsedDynamicAccountParameters> fieldParsedDynamicAccountParameters;
375
376 /**
377 * The Static Accounts for this task. These are setup when the task is
378 * configured.
379 */
380 private List<Account> fieldStaticAccounts;
381
382 /**
383 * The JavaMail Session for this fetch task.
384 */
385
386 private Session fieldSession;
387
388 /**
389 * The Dynamic Accounts for this task. These are setup each time the
390 * fetchtask is run.
391 */
392 private Map<DynamicAccountKey, DynamicAccount> fieldDynamicAccounts;
393
394 /**
395 * The Local Users repository
396 */
397 private UsersRepository fieldLocalUsers;
398
399 /**
400 * The DNSService
401 */
402 private DNSService dnsServer;
403
404 private Logger logger;
405
406 private MailQueue queue;
407
408 private DomainList domainList;
409
410 /**
411 * Constructor for POP3mail.
412 */
413 public FetchMail() {
414 super();
415 }
416
417 /**
418 * Method configure parses and validates the Configuration data and creates
419 * a new <code>ParsedConfiguration</code>, an <code>Account</code> for each
420 * configured static account and a
421 * <code>ParsedDynamicAccountParameters</code> for each dynamic account.
422 *
423 * @see org.apache.james.lifecycle.api.Configurable#configure(HierarchicalConfiguration)
424 */
425 @SuppressWarnings("unchecked")
426 public void configure(HierarchicalConfiguration configuration) throws ConfigurationException {
427 // Set any Session parameters passed in the Configuration
428 setSessionParameters(configuration);
429
430 // Create the ParsedConfiguration used in the delegation chain
431 ParsedConfiguration parsedConfiguration = new ParsedConfiguration(configuration, logger, getLocalUsers(), getDNSService(), getDomainList(), getMailQueue());
432
433 setParsedConfiguration(parsedConfiguration);
434
435 // Setup the Accounts
436 List<HierarchicalConfiguration> allAccounts = configuration.configurationsAt("accounts");
437 if (allAccounts.size() < 1)
438 throw new ConfigurationException("Missing <accounts> section.");
439 if (allAccounts.size() > 1)
440 throw new ConfigurationException("Too many <accounts> sections, there must be exactly one");
441 HierarchicalConfiguration accounts = allAccounts.get(0);
442
443 if (accounts.getKeys().hasNext() == false)
444 throw new ConfigurationException("Missing <account> section.");
445
446 List<Node> accountsChildren = accounts.getRoot().getChildren();
447 int i = 0;
448
449 // Create an Account for every configured account
450 for (Node accountsChild : accountsChildren) {
451
452 String accountsChildName = accountsChild.getName();
453
454 List<HierarchicalConfiguration> accountsChildConfig = accounts.configurationsAt(accountsChildName);
455 HierarchicalConfiguration conf = accountsChildConfig.get(i);
456
457 if ("alllocal".equals(accountsChildName)) {
458 // <allLocal> is dynamic, save the parameters for accounts to
459 // be created when the task is triggered
460 getParsedDynamicAccountParameters().add(new ParsedDynamicAccountParameters(i, conf));
461 continue;
462 }
463
464 if ("account".equals(accountsChildName)) {
465 // Create an Account for the named user and
466 // add it to the list of static accounts
467 getStaticAccounts().add(new Account(i, parsedConfiguration, conf.getString("[@user]"), conf.getString("[@password]"), conf.getString("[@recipient]"), conf.getBoolean("[@ignorercpt-header]"), conf.getString("[@customrcpt-header]", ""), getSession()));
468 continue;
469 }
470
471 throw new ConfigurationException("Illegal token: <" + accountsChildName + "> in <accounts>");
472 }
473 i++;
474 }
475
476 /**
477 * Method target triggered fetches mail for each configured account.
478 *
479 */
480 public void run() {
481 // if we are already fetching then just return
482 if (isFetching()) {
483 logger.info("Triggered fetch cancelled. A fetch is already in progress.");
484 return;
485 }
486
487 // Enter Fetching State
488 try {
489 setFetching(true);
490 logger.info("Fetcher starting fetches");
491
492 logJavaMailProperties();
493
494 // Update the dynamic accounts,
495 // merge with the static accounts and
496 // sort the accounts so they are in the order
497 // they were entered in config.xml
498 updateDynamicAccounts();
499 ArrayList<Account> mergedAccounts = new ArrayList<Account>(getDynamicAccounts().size() + getStaticAccounts().size());
500 mergedAccounts.addAll(getDynamicAccounts().values());
501 mergedAccounts.addAll(getStaticAccounts());
502 Collections.sort(mergedAccounts);
503
504 StringBuilder logMessage = new StringBuilder(64);
505 logMessage.append("Processing ");
506 logMessage.append(getStaticAccounts().size());
507 logMessage.append(" static accounts and ");
508 logMessage.append(getDynamicAccounts().size());
509 logMessage.append(" dynamic accounts.");
510 logger.info(logMessage.toString());
511
512 // Fetch each account
513 Iterator<Account> accounts = mergedAccounts.iterator();
514 while (accounts.hasNext()) {
515 try {
516 new StoreProcessor(accounts.next()).process();
517 } catch (MessagingException ex) {
518 logger.error("A MessagingException has terminated processing of this Account", ex);
519 }
520 }
521 } catch (Exception ex) {
522 logger.error("An Exception has terminated this fetch.", ex);
523 } finally {
524 logger.info("Fetcher completed fetches");
525
526 // Exit Fetching State
527 setFetching(false);
528 }
529 }
530
531 @SuppressWarnings("unchecked")
532 private void logJavaMailProperties() {
533 // if debugging, list the JavaMail property key/value pairs
534 // for this Session
535 if (logger.isDebugEnabled()) {
536 logger.debug("Session properties:");
537 Properties properties = getSession().getProperties();
538 Enumeration e = properties.keys();
539 while (e.hasMoreElements()) {
540 String key = (String) e.nextElement();
541 String val = (String) properties.get(key);
542 if (val.length() > 40) {
543 val = val.substring(0, 37) + "...";
544 }
545 logger.debug(key + "=" + val);
546
547 }
548 }
549 }
550
551 /**
552 * Returns the fetching.
553 *
554 * @return boolean
555 */
556 protected boolean isFetching() {
557 return fieldFetching;
558 }
559
560 /**
561 * Sets the fetching.
562 *
563 * @param fetching
564 * The fetching to set
565 */
566 protected void setFetching(boolean fetching) {
567 fieldFetching = fetching;
568 }
569
570 /**
571 * Returns the configuration.
572 *
573 * @return ParsedConfiguration
574 */
575 protected ParsedConfiguration getConfiguration() {
576 return fieldConfiguration;
577 }
578
579 /**
580 * Sets the configuration.
581 *
582 * @param configuration
583 * The configuration to set
584 */
585 protected void setParsedConfiguration(ParsedConfiguration configuration) {
586 fieldConfiguration = configuration;
587 }
588
589 /**
590 * Returns the localUsers.
591 *
592 * @return UsersRepository
593 */
594 protected UsersRepository getLocalUsers() {
595 return fieldLocalUsers;
596 }
597
598 /**
599 * Returns the DNSService.
600 *
601 * @return DNSService
602 */
603 protected DNSService getDNSService() {
604 return dnsServer;
605 }
606
607 public void setDNSService(DNSService dns) {
608 this.dnsServer = dns;
609 }
610
611 public void setUsersRepository(UsersRepository urepos) {
612 this.fieldLocalUsers = urepos;
613 }
614
615 public final void setLog(Logger logger) {
616 this.logger = logger;
617 }
618
619 /**
620 * Returns the accounts. Initializes if required.
621 *
622 * @return List
623 */
624 protected List<Account> getStaticAccounts() {
625 if (null == getStaticAccountsBasic()) {
626 updateStaticAccounts();
627 return getStaticAccounts();
628 }
629 return fieldStaticAccounts;
630 }
631
632 /**
633 * Returns the staticAccounts.
634 *
635 * @return List
636 */
637 private List<Account> getStaticAccountsBasic() {
638 return fieldStaticAccounts;
639 }
640
641 /**
642 * Sets the accounts.
643 *
644 * @param accounts
645 * The accounts to set
646 */
647 protected void setStaticAccounts(List<Account> accounts) {
648 fieldStaticAccounts = accounts;
649 }
650
651 /**
652 * Updates the staticAccounts.
653 */
654 protected void updateStaticAccounts() {
655 setStaticAccounts(computeStaticAccounts());
656 }
657
658 /**
659 * Updates the ParsedDynamicAccountParameters.
660 */
661 protected void updateParsedDynamicAccountParameters() {
662 setParsedDynamicAccountParameters(computeParsedDynamicAccountParameters());
663 }
664
665 /**
666 * Updates the dynamicAccounts.
667 */
668 protected void updateDynamicAccounts() throws ConfigurationException {
669 setDynamicAccounts(computeDynamicAccounts());
670 }
671
672 /**
673 * Computes the staticAccounts.
674 */
675 protected List<Account> computeStaticAccounts() {
676 return new ArrayList<Account>();
677 }
678
679 /**
680 * Computes the ParsedDynamicAccountParameters.
681 */
682 protected List<ParsedDynamicAccountParameters> computeParsedDynamicAccountParameters() {
683 return new ArrayList<ParsedDynamicAccountParameters>();
684 }
685
686 /**
687 * Computes the dynamicAccounts.
688 */
689 protected Map<DynamicAccountKey, DynamicAccount> computeDynamicAccounts() throws ConfigurationException {
690 Map<DynamicAccountKey, DynamicAccount> newAccounts;
691 try {
692 newAccounts = new HashMap<DynamicAccountKey, DynamicAccount>(getLocalUsers().countUsers() * getParsedDynamicAccountParameters().size());
693 } catch (UsersRepositoryException e) {
694 throw new ConfigurationException("Unable to acces UsersRepository", e);
695 }
696 Map<DynamicAccountKey, DynamicAccount> oldAccounts = getDynamicAccountsBasic();
697 if (null == oldAccounts)
698 oldAccounts = new HashMap<DynamicAccountKey, DynamicAccount>(0);
699
700 Iterator<ParsedDynamicAccountParameters> parameterIterator = getParsedDynamicAccountParameters().iterator();
701
702 // Process each ParsedDynamicParameters
703 while (parameterIterator.hasNext()) {
704 Map<DynamicAccountKey, DynamicAccount> accounts = computeDynamicAccounts(oldAccounts, (ParsedDynamicAccountParameters) parameterIterator.next());
705 // Remove accounts from oldAccounts.
706 // This avoids an average 2*N increase in heapspace used as the
707 // newAccounts are created.
708 Iterator<DynamicAccountKey> oldAccountsIterator = oldAccounts.keySet().iterator();
709 while (oldAccountsIterator.hasNext()) {
710 if (accounts.containsKey(oldAccountsIterator.next()))
711 oldAccountsIterator.remove();
712 }
713 // Add this parameter's accounts to newAccounts
714 newAccounts.putAll(accounts);
715 }
716 return newAccounts;
717 }
718
719 /**
720 * Returns the dynamicAccounts. Initializes if required.
721 *
722 * @return Map
723 */
724 protected Map<DynamicAccountKey, DynamicAccount> getDynamicAccounts() throws ConfigurationException {
725 if (null == getDynamicAccountsBasic()) {
726 updateDynamicAccounts();
727 return getDynamicAccounts();
728 }
729 return fieldDynamicAccounts;
730 }
731
732 /**
733 * Returns the dynamicAccounts.
734 *
735 * @return Map
736 */
737 private Map<DynamicAccountKey, DynamicAccount> getDynamicAccountsBasic() {
738 return fieldDynamicAccounts;
739 }
740
741 /**
742 * Sets the dynamicAccounts.
743 *
744 * @param dynamicAccounts
745 * The dynamicAccounts to set
746 */
747 protected void setDynamicAccounts(Map<DynamicAccountKey, DynamicAccount> dynamicAccounts) {
748 fieldDynamicAccounts = dynamicAccounts;
749 }
750
751 /**
752 * Compute the dynamicAccounts for the passed parameters. Accounts for
753 * existing users are copied and accounts for new users are created.
754 *
755 * @param oldAccounts
756 * @param parameters
757 * @return Map - The current Accounts
758 * @throws ConfigurationException
759 */
760 protected Map<DynamicAccountKey, DynamicAccount> computeDynamicAccounts(Map<DynamicAccountKey, DynamicAccount> oldAccounts, ParsedDynamicAccountParameters parameters) throws ConfigurationException {
761
762 Map<DynamicAccountKey, DynamicAccount> accounts;
763 Iterator<String> usersIterator;
764 try {
765 accounts = new HashMap<DynamicAccountKey, DynamicAccount>(getLocalUsers().countUsers());
766 usersIterator = getLocalUsers().list();
767
768 } catch (UsersRepositoryException e) {
769 throw new ConfigurationException("Unable to access UsersRepository", e);
770 }
771 while (usersIterator.hasNext()) {
772 String userName = usersIterator.next();
773 DynamicAccountKey key = new DynamicAccountKey(userName, parameters.getSequenceNumber());
774 DynamicAccount account = oldAccounts.get(key);
775 if (null == account) {
776 // Create a new DynamicAccount
777 account = new DynamicAccount(parameters.getSequenceNumber(), getConfiguration(), userName, parameters.getUserPrefix(), parameters.getUserSuffix(), parameters.getPassword(), parameters.getRecipientPrefix(), parameters.getRecipientSuffix(), parameters.isIgnoreRecipientHeader(),
778 parameters.getCustomRecipientHeader(), getSession());
779 }
780 accounts.put(key, account);
781 }
782 return accounts;
783 }
784
785 /**
786 * Resets the dynamicAccounts.
787 */
788 protected void resetDynamicAccounts() {
789 setDynamicAccounts(null);
790 }
791
792 /**
793 * Returns the ParsedDynamicAccountParameters.
794 *
795 * @return List
796 */
797 protected List<ParsedDynamicAccountParameters> getParsedDynamicAccountParameters() {
798 if (null == getParsedDynamicAccountParametersBasic()) {
799 updateParsedDynamicAccountParameters();
800 return getParsedDynamicAccountParameters();
801 }
802 return fieldParsedDynamicAccountParameters;
803 }
804
805 /**
806 * Returns the ParsedDynamicAccountParameters.
807 *
808 * @return List
809 */
810 private List<ParsedDynamicAccountParameters> getParsedDynamicAccountParametersBasic() {
811 return fieldParsedDynamicAccountParameters;
812 }
813
814 /**
815 * Sets the ParsedDynamicAccountParameters.
816 *
817 * @param parsedDynamicAccountParameters
818 * The ParsedDynamicAccountParameters to set
819 */
820 protected void setParsedDynamicAccountParameters(List<ParsedDynamicAccountParameters> parsedDynamicAccountParameters) {
821 fieldParsedDynamicAccountParameters = parsedDynamicAccountParameters;
822 }
823
824 /**
825 * Returns the session, lazily initialized if required.
826 *
827 * @return Session
828 */
829 protected Session getSession() {
830 Session session = null;
831 if (null == (session = getSessionBasic())) {
832 updateSession();
833 return getSession();
834 }
835 return session;
836 }
837
838 /**
839 * Returns the session.
840 *
841 * @return Session
842 */
843 private Session getSessionBasic() {
844 return fieldSession;
845 }
846
847 /**
848 * Answers a new Session.
849 *
850 * @return Session
851 */
852 protected Session computeSession() {
853 // Make separate properties instance so the
854 // fetchmail.xml <javaMailProperties> can override the
855 // property values without interfering with other fetchmail instances
856 return Session.getInstance(new Properties(System.getProperties()));
857 }
858
859 /**
860 * Updates the current Session.
861 */
862 protected void updateSession() {
863 setSession(computeSession());
864 }
865
866 /**
867 * Sets the session.
868 *
869 * @param session
870 * The session to set
871 */
872 protected void setSession(Session session) {
873 fieldSession = session;
874 }
875
876 /**
877 * Propagate any Session parameters in the configuration to the Session.
878 *
879 * @param configuration
880 * The configuration containing the parameters
881 * @throws ConfigurationException
882 */
883 @SuppressWarnings("unchecked")
884 protected void setSessionParameters(HierarchicalConfiguration configuration) throws ConfigurationException {
885
886 if (configuration.getKeys("javaMailProperties.property").hasNext()) {
887 Properties properties = getSession().getProperties();
888 List<HierarchicalConfiguration> allProperties = configuration.configurationsAt("javaMailProperties.property");
889 for (int i = 0; i < allProperties.size(); i++) {
890 HierarchicalConfiguration propConf = allProperties.get(i);
891 properties.setProperty(propConf.getString("[@name]"), propConf.getString("[@value]"));
892 if (logger.isDebugEnabled()) {
893 StringBuilder messageBuffer = new StringBuilder("Set property name: ");
894 messageBuffer.append(propConf.getString("[@name]"));
895 messageBuffer.append(" to: ");
896 messageBuffer.append(propConf.getString("[@value]"));
897 logger.debug(messageBuffer.toString());
898 }
899 }
900 }
901 }
902
903 public void setMailQueue(MailQueue queue) {
904 this.queue = queue;
905 }
906
907 public MailQueue getMailQueue() {
908 return queue;
909 }
910
911 public void setDomainList(DomainList domainList) {
912 this.domainList = domainList;
913 }
914
915 public DomainList getDomainList() {
916 return domainList;
917 }
918 }