/*
 * $Id: DocPublishNotification.java,v 1.45 2008/04/17 10:01:00 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: DocPublishNotification.java,v $
 * Revision 1.45  2008/04/17 10:01:00  marbobo
 * + Velocity-Templates angepasst
 *
 * Revision 1.44  2008/02/28 15:45:40  korowa
 * +bugfixing
 *
 * Revision 1.43  2008/02/12 10:38:43  korowa
 * bugfixing: der Betreff wird jetzt kodiert an den DB übergeben
 *
 * Revision 1.42  2008/02/12 09:39:58  korowa
 * + Eine Möglichkeit für den Benutzer hinzugefügt die Emailsart auszuwählen (HTML oder Plaintext)
 * + Betreff für den Messenger der als Emailsubject bei Benachrichtigung übers erscheinen von VKC Dokumenten verschickt wird.
 *
 * Revision 1.41  2007/08/08 12:14:39  marbobo
 * + License-Funktionalität komplett umgeschrieben
 * + Bugfix bzgl. Beschreibungsfelder von Entitäten
 * + Bugfix mailing
 *
 * Revision 1.40  2007/07/27 11:14:29  marbobo
 * + Ungenutzte Anweisungen entfernt
 *
 * Revision 1.39  2006/12/21 13:02:54  lawern
 * WhatsRelated auch noch umgestellt.
 *
 * Revision 1.38  2006/12/21 12:08:41  lawern
 * Benachrichtigung zu registrierten Suchanfragen überarbeitet.
 *
 * Revision 1.37  2006/10/04 03:15:15  marbobo
 * + Vollständige Unterstützung für Templates implementiert
 * + Alles von Virtoweb auf ProCoBa umgestellt
 *
 * Revision 1.36  2006/09/10 20:46:55  marbobo
 * + Bugfix
 *
 * Revision 1.35  2006/09/06 15:15:28  marbobo
 * + Bugfix
 *
 * Revision 1.34  2005/12/15 15:28:51  marbobo
 * + Benutzername und Passwort für Mailserver implementiert
 *
 * Revision 1.33  2005/09/13 09:51:44  jonyp
 * cleaning the code
 *
 * Revision 1.32  2005/09/13 08:40:36  jonyp
 * added DBExceptions due to chance of method getDocumentId in VKCDocument
 *
 * Revision 1.31  2005/07/28 19:57:24  marbobo
 * + Template-Pfade angepasst
 *
 * Revision 1.30  2005/07/04 18:24:52  marbobo
 * + Email-Anzeige für Suchanfragen korrigiert
 *
 * Revision 1.29  2005/04/12 12:56:05  korowa
 * Neuer path für Velocity Engine gesetzt, Head.txt enthält jetzt die gemeinsame Eigenschaften
 * (header,css-Teil und importiertes Bild)die früher in jeder Mail- HTML-Datei  standen.
 *
 * Revision 1.28  2005/02/15 18:44:51  marbobo
 * + Unicode-Konforme E-Mails
 *
 * Revision 1.27  2005/02/10 14:45:05  marbobo
 * + Unicode-Anzeige bei Emails
 *
 * Revision 1.26  2005/02/08 15:48:59  jonyp
 * + try catch in main while-loop of run-method to force thread to run forever
 *
 * Revision 1.25  2005/01/28 15:32:19  jonyp
 * added some code to prevent dockeywords/docdescription to be null in hashmap for velocity
 *
 * Revision 1.24  2005/01/28 09:57:16  bigmac
 * Anzahl der Dokumente im Subject der Benachrichtigungsmail begrenzt
 *
 * Revision 1.23  2004/11/10 15:02:48  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.22  2004/11/09 14:35:36  marbobo
 * + Umstellung von authorId auf publisherId
 * + Hinzufügen von AuthorName für Dokumente
 * + Nötwendige Änderungen betreffend AuthorName und PublisherId
 *
 * Revision 1.21  2004/10/06 12:33:39  marbobo
 * + Suche nach Globalen Dokument-Attributen korrigiert
 *
 * Revision 1.20  2004/09/03 00:42:43  marbobo
 * + Kategorieauswahl über ein Explorer für die Suche eingebaut
 *
 * Revision 1.19  2004/08/21 17:01:16  koppy
 * Subject in application.properties ausgelagert
 *
 * Revision 1.18  2004/08/20 12:48:26  koppy
 * Etwas überarbeitet + Behandlung von registrierten Queries
 *
 * Revision 1.17  2004/08/04 13:45:51  marbobo
 * + Bugfix (MessagingTimePeriod)
 *
 * Revision 1.16  2004/08/04 11:24:03  marbobo
 * + Bugfix (MessagingTimePeriod)
 *
 * Revision 1.15  2004/07/20 08:28:18  jonyp
 * added copyright info + cvs log
 *
 * Revision 1.14  2004/06/27 17:21:28  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.10  2004/03/12 15:44:17  bigmac
 * Methoden für (lokale) zusätzliche Attribute aus VKCDynAttributeSerializer
 * nach VKCAddAttributeSerializer verschoben
 *
 * Revision 1.9  2004/03/11 20:17:14  bigmac
 * Anpassungen an VKCUserSerializer
 *
 * Revision 1.8  2004/03/11 17:35:10  teng
 * zusaetzliche Methode isTimeToSetInvalid(...)
 *
 * Revision 1.7  2004/03/09 18:40:34  bigmac
 * Anpassungen an VKCSysParameterSerializer
 *
 * Revision 1.4  2004/03/02 23:05:42  bigmac
 * Anpassungen an VKCDocumentSerializer und VKCCategorySerializer
 *
 */
package vkc.messenger.mail;

import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Sort;

import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCDocument;
import vkc.db.entities.VKCSearchQuery;
import vkc.db.entities.VKCUser;
import vkc.db.entities.VKCUserDocMail;

import vkc.db.serializer.VKCCategorySerializer;
import vkc.db.serializer.VKCUserSerializer;

import vkc.exception.DBException;

import vkc.misc.VKCLogManager;

import vkc.search.Search;

import vkc.util.ServletUtils;
import vkc.util.StringUtils;
import vkc.util.VKCStringUtils;

import vkc.view.WebShare;

import vkc.view.bean.ResourceInfo;

import java.io.IOException;

import java.sql.Timestamp;

import java.text.SimpleDateFormat;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

/**
 * Klasse fuer die Benachrichtigung, wenn ein Dokument veroeffentlicht ist.
 * @author teng
 */
public class DocPublishNotification extends NotificationMail {
    private final static int MAX_DOCS_IN_SUBJECT = 3;

    /**
     * Enthält die aktuellen UserDocMails, die gerade aus der DB ausgelesen
     * werden.
     */
    private Collection userDocMails;

    /** Enthält die UserDocMails, die sofort abgeschickt werden sollen. */
    private Vector userDocMailsToProcess = new Vector();
    private VKCUserDocMail userDocMail;

    /**
     * Bestimmen wie lange dieser Thread schlafen soll. Das wird normalerweise
     * benutzt, wenn es keinen neuen Auftrag gibt.
     */
    private long sleepingTime = 100000;

    /**
     * Da es evtl. UserDocMails gibt, die nach bestimmter Zeit abgeschickt
     * werden sollen, wird die Schlafzeit dieses Threads neu eingestellt.
     */
    private long newTimeToSleep = 0;

    /**
     * Die Anzahl der UserDocMails, die in der Datenbank noch nicht bearbeitet
     * werden.
     */
    private int mailCount = 0;

    /** Schlaeft dieser Thread gerade? */
    private boolean sleeping = false;

    /**
     * Nachdem dieser Thread gerade Emails bearbeitet hat, prueft er
     * durch diese Variable, ob inzwischen ein neues Dokument veroeffentlicht wird.
     * Der Vorteil ist, dass die andere Prozesse nicht durch synchronized blockiert werden (ohne diese Variable muss checkMail() synchronized sein).
     *
     * @see checkMail()
     */
    private boolean newDocPublished = false;

    /**
     *
     */
    public DocPublishNotification() {
        super();
    }

    public void run() {
        try {
            if (!init()) {
                VKCLogManager.infoLog(this, "Init VKCDocPublishMail failed...");

                return;
            }

            while (true) {
                try {
                    while (!isEnabled()) { //Dieser Thread arbeitet nicht wenn er deaktiviert wird   

                        try {
                            sleeping = true;
                            sleep(sleepingTime);
                            sleeping = false;
                        } catch (InterruptedException iex) {
                            //break;
                        }
                    }

                    if (debug) {
                        VKCLogManager.infoLog(this, "DocPublishNotification is running...");
                    }

                    try {
                        userDocMails = mailManager.getUserDocMails();

                        synchronized (this) {
                            newDocPublished = false;
                        }

                        mailCount = userDocMails.size();

                        for (Iterator it = userDocMails.iterator(); it.hasNext();) {
                            userDocMail = (VKCUserDocMail) it.next();

                            //check time to send
                            Timestamp sendOnTimestamp = userDocMail.getSendOn();

                            if (userDocMail.getProcessedIntValue() == VKCUserDocMail.NOT_PROCESSED) {
                                long currentTime = System.currentTimeMillis();
                                long sendOnTime = sendOnTimestamp.getTime();

                                if ((sendOnTime - currentTime) > 1000) {
                                    //ignore time shorter than 1000 ms
                                    newTimeToSleep = sendOnTime - currentTime;
                                } else { //this userDocMail should be sended
                                    userDocMailsToProcess.add(userDocMail);
                                }
                            } else {
                                if (userDocMail.isTimeToSetInvalid()) {
                                    mailManager.setUserDocMailInvalid(userDocMail.getUdmId());
                                }

                                if (userDocMail.isTimeToDelete()) {
                                    mailManager.deleteUserDocMail(userDocMail.getUdmId());
                                }

                                mailCount--;
                            }
                        }

                        //process
                        int docMailCount = userDocMailsToProcess.size();
                        mailCount -= docMailCount;

                        if (docMailCount > 0) {
                            /* int k = sendMail(userDocMailsToProcess);
                             if ((docMailCount - k) > 0) {//Hier gibt's Emails, die nicht abgesendet werden koennen
                                     sleepingTime += 10000;//Verlaengern die Schlafenzeit, um kurz danach sinnlose Wiederversuche zu vermeiden
                             }
                             mailCount = mailCount - k;*/
                            sendMail(userDocMailsToProcess);
                            userDocMailsToProcess.removeAllElements();
                        }
                    } catch (DBException dbex) {
                        VKCLogManager.infoLog(this, "" + dbex);

                        //sleepingTime += 10000;//warte fuer laengere Zeit, wenn eine Exception ausloest wird
                    }

                    if (mailCount == 0) { //go to sleep
                        sleepingTime = 100000;

                        //sleep forever until this thread is interrupted or there are mails still not be sended
                        while (!newDocPublished) {
                            try {
                                sleeping = true;
                                sleep(sleepingTime);
                                sleeping = false;
                            } catch (InterruptedException iex) {
                                break;
                            }
                        }
                    } else if (!newDocPublished) { //go to sleep
                        //if there is just one userdocmail not sended, set the longer time to sleep
                        if (((mailCount == 1) && (sleepingTime < newTimeToSleep)) || (sleepingTime > newTimeToSleep)) {
                            //else set the shortest user preferred delay time to the timeToSleep
                            sleepingTime = newTimeToSleep;
                        }

                        try {
                            sleeping = true;
                            sleep(sleepingTime);
                            sleeping = false;
                        } catch (InterruptedException iex) {
                        }
                    }
                } catch (Exception ex) {
                    VKCLogManager.errorLog(this, "1", "DocPublishNotification thread caught exception -> continue execution",
                        ex);

                    continue;
                }
            }
        } catch (Exception ex) {
            VKCLogManager.errorLog(this, "", "run failed: ", ex);
        }
    }

    /**
     * This method will interrupt this Thread if it is sleeping. Use this method to notify this thread to check database for emails
     */
    public void wakeUp() {
        if (!isEnabled()) { //Deaktiviert, weiter schlafen.

            return;
        }

        synchronized (this) {
            newDocPublished = true;
        }

        if (!this.isInterrupted() && sleeping) {
            synchronized (this) {
                sleeping = false;
            }

            this.interrupt();
        }
    }

    /**
     * Send mails for the given <code>UserDocMail</code>s
     *
     * @param udmToProcess contains <code>UserDocMail</code>s which should be
     *        sent.
     *
     * @return
     */
    private int sendMail(Vector udmToProcess) {
        VKCUser user = null;
        VKCUser publisher = null;

        String subject;
        String docTitle = "";
        String dateString;
        String authorName;
        String publisherEmail;
        int sendedMailCount = 0;
        String asciiText = null;
        String htmlText = null;

        String docDescription = null;
        String docKeywords = null;
        String docName = null;
        VKCDocument relDoc = null;
        String relDocName = null;
        String relDocUrl = null;
        String categoryName = null;
        String categoryURL = null;
        Integer docId = null;
        Integer catId = null;
        Vector docInfos = new Vector();

        HashMap map = mapUserDocMail(udmToProcess);

        Set keys = map.keySet();
        Vector udms;
        
        String subjectForNotification = null;
        for (Iterator mapit = keys.iterator(); mapit.hasNext();) {
            //Bearbeiten Emails fuer einen User
            Integer userId = (Integer) mapit.next();
            udms = (Vector) map.get(userId);
            Vector udmsUpdate = (Vector) udms.clone();
            user = ((VKCUserDocMail) udms.get(0)).getUser();

            recepient = VKCStringUtils.decodeXmlEntities(user.getEmail());
            language = user.getLanguage();
            
            subject = WebShare.resources.getMessage(language.getLocale(), "vkc.messenger.docsPublishedSubject");

            docInfos.removeAllElements();

            int numDocsInSubject = 0;
            while(!udms.isEmpty()){
            //alle Emails fuer diesen User in einer Email zusammensetzen
            for (Iterator it = udms.iterator(); it.hasNext();) {
                VKCUserDocMail udm = (VKCUserDocMail) it.next();

                if(subjectForNotification==null || subjectForNotification.equals(udm.getSubject())){
                    it.remove();
                    subjectForNotification = udm.getSubject();
                    VKCDocument doc = udm.getDocument();
                    VKCSearchQuery query = udm.getRelQuery();
                    docId = doc.getDocumentId();
                    catId = doc.getCategoryId();
                    relDoc = udm.getRelDoc();
    
                    if (relDoc != null) {
                        relDocName = relDoc.getName();
                    }
    
                    docTitle = doc.getTitle();
    
                    if ((numDocsInSubject < MAX_DOCS_IN_SUBJECT) && !StringUtils.isEmpty(docTitle)) {
                        subject += (" <" + VKCStringUtils.decodeXmlEntities(docTitle) + ">");
                        numDocsInSubject++;
                    }
    
                    if (numDocsInSubject == MAX_DOCS_IN_SUBJECT) {
                        subject += " ...";
                        numDocsInSubject++;
                    }
    
                    docDescription = doc.getDescription();
                    docKeywords = doc.getKeywordsAsString();
                    docName = doc.getName();
                    dateString = new SimpleDateFormat(WebShare.resources.getMessage(language.getLocale(), "date.medium.format")).format(doc.getPublished());
    
                    //prepare category
                    try {
                        if (catId != null) {
                       
    
                        categoryURL = vkc_rootURL + catURL + catId.intValue();
    
                        VKCCategory cat = VKCCategorySerializer.retrieveCategory(catId);
    
                        // create category name displayed
                        categoryName = cat.getName();
    
                        //inclusive all parent categories
                        Integer parent = cat.getParentCategoryId();
    
                        while (parent != null) {
                            cat = VKCCategorySerializer.retrieveCategory(parent);
                            categoryName = cat.getName() + "/" + categoryName;
                            parent = cat.getParentCategoryId();
                        }
    
                        if (relDoc != null) {
                            relDocUrl = vkc_rootURL + docURL + relDoc.getDocumentId();
                        }
                       
                        }
                    } catch (DBException dbex) {
                        VKCLogManager.errorLog(this, "", dbex.getMessage(), dbex);
    
                        continue;
                    }
    
                    try {
                        publisher = VKCUserSerializer.retrieveUser(doc.getPublisherId());
                        authorName = doc.getAuthorName();
    
                        if (publisher.getShowEmail()) {
                            publisherEmail = publisher.getEmail();
                        } else {
                            publisherEmail = null;
                        }
                    } catch (DBException dbex) {
                        VKCLogManager.errorLog(this, "", "VKCDocPublishMail.sendMail():", dbex);
    
                        continue;
                    }
    
                    createTemplateParser();
    
                    if (plainTemplateParser != null || htmlTemplateParser != null) {
                        valueMap = new HashMap();
    
                        valueMap.put("docname", VKCStringUtils.filterUnicodeChars(docName));
                        valueMap.put("doctitle",VKCStringUtils.filterUnicodeChars(docTitle));
                        valueMap.put("date", dateString);
                        valueMap.put("authorname", VKCStringUtils.filterUnicodeChars(authorName));
                        valueMap.put("publishername", VKCStringUtils.filterUnicodeChars(publisher.getLastnameLabel()));
                        valueMap.put("docurl", vkc_rootURL + docURL + docId.intValue());
                        valueMap.put("categoryurl", categoryURL);
                        valueMap.put("categoryname", VKCStringUtils.filterUnicodeChars(categoryName));
    
                        if (!StringUtils.isEmpty(docKeywords)) {
                            valueMap.put("dockeywords", VKCStringUtils.filterUnicodeChars(docKeywords));
                        } else {
                            valueMap.put("dockeywords", "");
                        }
    
                        if (!StringUtils.isEmpty(docDescription)) {
                            valueMap.put("docdescription", VKCStringUtils.filterUnicodeChars(docDescription));
                        } else {
                            valueMap.put("docdescription", "");
                        }
    
                        if (publisherEmail != null) {
                            valueMap.put("email", publisherEmail);
                        }
    
                        if (relDoc != null && relDoc.getDocumentId() != null && relDocName != null && relDocUrl != null) {
                            // Die Suche wird deshalb nochmal durchgeführt,
                            // um die Trefferquote zu ermitteln und anzuzeigen.
                            // Alternativ könnte man sie auch in der USERDOCMAILS-Tabelle
                            // beim Populieren speichern. Was ist besser?
                            Hits relDocuments = null;
    
                            try {
                                relDocuments = Search.whatsRelated(doc, null, null, "*", 
                                        null, null, null, null, new Sort());
                            } catch (Exception ex) {
                                VKCLogManager.errorLog(this, "", "WhatsRelated failed for document " + doc.getName(), ex);
                            }
    
                            if (relDocuments != null) {
                                int relDocumentsLength = relDocuments.length();
    
                                for (int i = 0; i < relDocumentsLength; i++) {
                                    try {
                                        if (relDoc.getDocumentId().equals(new Integer(relDocuments.doc(i).get("documentId")))) {
                                            valueMap.put("reldocurl", relDocUrl);
                                            valueMap.put("reldocname", VKCStringUtils.filterUnicodeChars(relDocName));
                                            valueMap.put("reldocpercent", String.valueOf(Math.round(relDocuments.score(i) * 10000) / 100.0));
    
                                            break;
                                        }
                                    } catch (NumberFormatException e) {
                                        e.printStackTrace();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
    
                            Search.searchFinished();
                        }
    
                        if (query != null) {
                            // Die Suche wird deshalb nochmal durchgeführt,
                            // um die Trefferquote zu ermitteln und anzuzeigen.
                            // Alternativ könnte man sie auch in der USERDOCMAILS-Tabelle
                            // beim Populieren speichern. Was ist besser?
                            Hits results = Search.search(query.getSearchQuery(),
                                    query.getFrom(), query.getUntil(),
                                    query.getSelectedResultLimitation(), user,
                                    query.getCategoryId(), null, null, new Sort());
    
                            if(results!= null){
                            int resultsLength = results.length();
    
                            for (int i = 0; i < resultsLength; i++) {
                                try {
                                    if (doc.getDocumentId().equals(new Integer(results.doc(i).get("documentId")))) {
                                        try {
                                            valueMap.put("queryhtml", query.getLocalizedHTMLString(WebShare.resources, language.getLocale(), false, false));
                                            valueMap.put("queryascii", VKCStringUtils.filterUnicodeChars(query.getLocalizedASCIIString(WebShare.resources, language.getLocale(), false, false)));
                                            valueMap.put("querypercent", String.valueOf(Math.round(results.score(i) * 10000) / 100.0));
                                        } catch (DBException e) {
                                            VKCLogManager.errorLog(this, "", e.getMessage(), e);
                                        }
    
                                        break;
                                    }
                                } catch (NumberFormatException e) {
                                    e.printStackTrace();
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                            }
                            Search.searchFinished();                        
                        }
    
                        docInfos.add(valueMap); //one docInfo 
                    }
                }
            } //all documents ready

            HashMap context = new HashMap();
            context.put("language", language.getShortName());
            context.put("adminEmail", senderAddr);
            context.put("docInfos", docInfos);
            context.put("fullname", VKCStringUtils.filterUnicodeChars(user.getFirstname() + " " + user.getLastname()));
            context.put("resources", new ResourceInfo(WebShare.resources, language.getLocale()));
            context.put("vkcstringutils", new VKCStringUtils());
            context.put("template", user.getTemplate().getName());

            //--------- data in the email body for this user is ready -----------
            if (plainTemplateParser != null) {
                plainTemplateParser.setContextData(context);

                String asciiPath = "templates/${template.name}/velocitytemplates/mail/doc_publish_notification.plain";
                asciiText = plainTemplateParser.createString(ServletUtils.replacePathVars(asciiPath, user));
            }

            if (htmlTemplateParser != null) {
                htmlTemplateParser.setContextData(context);

                String htmlPath = "templates/${template.name}/velocitytemplates/mail/doc_publish_notification.html";
                htmlText = htmlTemplateParser.createString(ServletUtils.replacePathVars(htmlPath, user));
            }

            try {
                if (debug) {
                    VKCLogManager.infoLog(this, "Sending SMTPMail no. " + sendedMailCount + "...");
                }

                mailUtils.setUser(user);
                if(user.isEnableHtmlNotification()){
                    mailUtils.sendSMTPMailWithVKCLogo(senderAddr, recepient, VKCStringUtils.decodeXmlEntities(subjectForNotification)+" "+subject, asciiText, htmlText, null, null, smtpServer, smtpUsername, smtpPassword);
                }else{
                    mailUtils.sendSMTPMail(senderAddr, recepient, VKCStringUtils.decodeXmlEntities(subjectForNotification)+" "+subject, asciiText, null, null, null, smtpServer, smtpUsername, smtpPassword);
                }
                sendedMailCount++;
                updateDB(udmsUpdate);
            } catch (Exception iex) {
                VKCLogManager.errorLog(this, "", "Failed!", iex);
            }

            asciiText = null;
            subject = WebShare.resources.getMessage(language.getLocale(), "vkc.messenger.docsPublishedSubject");
            plainTemplateParser = null;
            htmlTemplateParser = null;
            docInfos.removeAllElements();
            subjectForNotification=null;
        }
        }

        return sendedMailCount;
    }

    /**
     * @param udms Vector contains <code>UserDocMail</code>s
     *
     * @return HashMap( Key:UserId, Value:Vector ), the Vector contains
     *         UserDocMail for the UserId
     */
    private HashMap mapUserDocMail(Vector udms) {
        HashMap map = new HashMap();
        Vector v = new Vector();

        VKCUserDocMail udm = (VKCUserDocMail) udms.remove(0);
        Integer userId = udm.getUser().getUserId();
        v.add(udm);
        map.put(userId, v);

        while (!udms.isEmpty()) {
            udm = (VKCUserDocMail) udms.remove(0);
            userId = udm.getUser().getUserId();

            if (map.containsKey(userId)) {
                ((Vector) map.get(userId)).add(udm);
            } else {
                v = new Vector();
                v.add(udm);
                map.put(userId, v);
            }
        }

        return map;
    }

    /**
     * Set userdocmail in DB as processed
     *
     * @param udms
     */
    private void updateDB(Vector udms) {
        //update database
        for (Iterator it = udms.iterator(); it.hasNext();) {
            VKCUserDocMail udm = (VKCUserDocMail) it.next();

            try {
                mailManager.setUserDocMailProcessed(udm.getUdmId());
            } catch (DBException dbEx) {
                VKCLogManager.errorLog(this, "", "Update of processed userdocmails failed!", dbEx);
            }
        }
    }
}