Package com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter

Source Code of com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.NewsletterManager

/*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
* This file is part of Entando software.
* Entando is a free software;
* You can redistribute it and/or modify it
* under the terms of the GNU General Public License (GPL) as published by the Free Software Foundation; version 2.
*
* See the file License for the specific language governing permissions  
* and limitations under the License
*
*
*
* Copyright 2013 Entando S.r.l. (http://www.entando.com) All rights reserved.
*
*/
package com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringEscapeUtils;

import com.agiletec.aps.system.ApsSystemUtils;
import com.agiletec.aps.system.SystemConstants;
import com.agiletec.aps.system.common.AbstractService;
import com.agiletec.aps.system.common.entity.IEntityManager;
import com.agiletec.aps.system.common.entity.model.EntitySearchFilter;
import com.agiletec.aps.system.exception.ApsSystemException;
import com.agiletec.aps.system.services.authorization.IApsAuthority;
import com.agiletec.aps.system.services.authorization.authorizator.IApsAuthorityManager;
import com.agiletec.aps.system.services.baseconfig.ConfigInterface;
import com.agiletec.aps.system.services.category.Category;
import com.agiletec.aps.system.services.group.Group;
import com.agiletec.aps.system.services.keygenerator.IKeyGeneratorManager;
import com.agiletec.aps.system.services.lang.ILangManager;
import com.agiletec.aps.system.services.user.IUserManager;
import com.agiletec.aps.system.services.user.UserDetails;
import com.agiletec.aps.util.DateConverter;
import com.agiletec.plugins.jacms.aps.system.services.content.IContentManager;
import com.agiletec.plugins.jacms.aps.system.services.content.model.Content;
import com.agiletec.plugins.jacms.aps.system.services.linkresolver.ILinkResolverManager;
import com.agiletec.plugins.jacms.aps.system.services.renderer.IContentRenderer;
import com.agiletec.plugins.jpmail.aps.services.mail.IMailManager;
import com.agiletec.plugins.jpmail.aps.services.mail.MailSendersUtilizer;
import com.agiletec.plugins.jpnewsletter.aps.system.JpnewsletterSystemConstants;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.model.ContentReport;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.model.NewsletterConfig;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.model.NewsletterContentReportVO;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.model.NewsletterContentType;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.model.NewsletterReport;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.model.NewsletterSearchBean;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.model.Subscriber;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.parse.NewsletterConfigDOM;
import com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.util.ShaEncoder;
import java.security.NoSuchAlgorithmException;
import org.entando.entando.aps.system.services.userprofile.IUserProfileManager;
import org.entando.entando.aps.system.services.userprofile.model.IUserProfile;

/**
* Servizio gestore delle newsletter.
* @author E.Santoboni, A.Turrini, E.Mezzano
*/
public class NewsletterManager extends AbstractService
    implements INewsletterManager, MailSendersUtilizer, INewsletterSchedulerManager {
 
  @Override
  public void init() throws Exception {
    this.loadConfigs();
    this.startScheduler();
    ApsSystemUtils.getLogger().debug(this.getClass().getName() + ": initialized");
  }
 
  @Override
  public void refresh() throws Throwable {
    synchronized (this) {
      super.refresh();
    }
  }
 
  @Override
  protected void release() {
    this._scheduler.cancel();
    this._scheduler = null;
  }
 
  @Override
  public void destroy() {
    this._scheduler.cancel();
    this._scheduler = null;
  }
 
  /**
   * Carica e salva la configurazione di sistema del servizio.
   * @throws ApsSystemException
   */
  protected void loadConfigs() throws ApsSystemException {
    try {
      ConfigInterface configManager = this.getConfigManager();
      String xml = configManager.getConfigItem(JpnewsletterSystemConstants.NEWSLETTER_CONFIG_ITEM);
      if (xml == null) {
        throw new ApsSystemException("Configuration item not present: " + JpnewsletterSystemConstants.NEWSLETTER_CONFIG_ITEM);
      }
      NewsletterConfigDOM configDOM = new NewsletterConfigDOM();
      this.setConfig(configDOM.extractConfig(xml));
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "loadConfigs");
      throw new ApsSystemException("Errore in fase di inizializzazione", t);
    }
  }
 
  @Override
  public void startScheduler() throws ApsSystemException {
    NewsletterConfig config = this.getConfig();
    Date start = config.getNextTaskTime();
    this._scheduler = new Scheduler(this, start, config.getHoursDelay());
  }
 
  /**
   * Restart the scheduler at the intended time and NOT at the next iteration. This may
   * result in an immediate execution of the delivery process
   * @param config
   */
  private void restartScheduler(NewsletterConfig config) {
    Date start = config.getStartScheduler();
    this._scheduler = new Scheduler(this, start, config.getHoursDelay());
  }
 
  @Override
  public void stopScheduler() throws ApsSystemException {
    this.release();
  }
 
  @Override
  public NewsletterConfig getNewsletterConfig() {
    return this._config.clone();
  }
 
  @Override
  public void updateNewsletterConfig(NewsletterConfig config) throws ApsSystemException {
    Date originalStartDate = null;
    try {
      originalStartDate = this.getConfig().getStartScheduler();
      String xml = new NewsletterConfigDOM().createConfigXml(config);
      this.getConfigManager().updateConfigItem(JpnewsletterSystemConstants.NEWSLETTER_CONFIG_ITEM, xml);
      this.setConfig(config);
      // restart the scheduler if necessary
      if (originalStartDate.getTime() != config.getStartScheduler().getTime()) {
        ApsSystemUtils.getLogger().info("Newsletter: scheduler restart issued");
        stopScheduler();
        restartScheduler(config);
        ApsSystemUtils.getLogger().info("Newsletter: scheduler restart completed");
      }
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "updateNewsletterConfig");
      throw new ApsSystemException("Errore in fase di aggiornamento configurazione newsletter", t);
    }
  }
 
  @Override
  public void addContentToQueue(String contentId) throws ApsSystemException {
    try {
      this.getNewsletterDAO().addContentToQueue(contentId);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "addContentToQueue");
      // Do not throws exceptions
    }
  }
 
  @Override
  public void removeContentFromQueue(String contentId) throws ApsSystemException {
    try {
      this.getNewsletterDAO().deleteContentFromQueue(contentId);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "removeContentFromQueue");
      throw new ApsSystemException("Errore in aggiunta contenuto in coda newsLetter", t);
    }
  }
 
  @Override
  public List<String> getContentQueue() throws ApsSystemException {
    try {
      return this.getNewsletterDAO().loadContentQueue();
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "getContentQueue");
      throw new ApsSystemException("Errore in caricamento coda contenuti newsLetter", t);
    }
  }
 
  @Override
  public boolean existsContentReport(String contentId) throws ApsSystemException {
    try {
      return this.getNewsletterDAO().existsContentReport(contentId);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "getContentQueue");
      throw new ApsSystemException("Error verifying content report existence", t);
    }
  }
 
  @Override
  public List<String> getSentContentIds() throws ApsSystemException {
    try {
      return this.getNewsletterDAO().loadSentContentIds();
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "getContentQueue");
      throw new ApsSystemException("Error loading sent contents ids", t);
    }
  }
 
  @Override
  public NewsletterContentReportVO getContentReport(String contentId) throws ApsSystemException {
    try {
      return this.getNewsletterDAO().loadContentReport(contentId);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "getContentQueue");
      throw new ApsSystemException("Error loading content report", t);
    }
  }
 
  /**
   * Istanzia un thread che esegue l'invio della newsletter.
   * Verifica che in ogni istante sia in esecuzione al più un processo di invio della newsletter.
   * @throws ApsSystemException In caso di errore.
   */
  @Override
  public void sendNewsletter() throws ApsSystemException {
    if (!this.isSendingNewsletter() && this.getContentQueue().size()>0) {
      NewsletterSenderThread sender = new NewsletterSenderThread(this);
      sender.setName(JpnewsletterSystemConstants.NEWSLETTER_SENDER_THREAD_NAME);
      sender.start();
    }
  }
 
  protected void sendNewsletterFromThread() throws ApsSystemException {
    synchronized (this) {
      if (this.isSendingNewsletter()) {
        return;
      } else {
        this.setSendingNewsletter(true);
      }
    }
    try {
      ApsSystemUtils.getLogger().info("Newletter: delivery process initiated");
      if (!this.getConfig().isActive()) return;
      List<String> contentIds = this.getContentQueue();
      if (contentIds.size() > 0) {
        List<Content> contents = new ArrayList<Content>(contentIds.size());
        for (int i = 0; i < contentIds.size(); i++) {
          String id = contentIds.get(i);
          Content content = this.getContentManager().loadContent(id, true);
          if (content != null) {
            contents.add(content);
          }
        }
        if (contents.size() > 0) {
          this.sendNewsletterToUsers(contents);
        } else {
          ApsSystemUtils.getLogger().info("Newletter: had some contents ids selected, corresponding to no actual content: this is quite strange!");
        }
        this.getNewsletterDAO().cleanContentQueue(contentIds);
      } else {
        ApsSystemUtils.getLogger().info("Newletter: no contents found for delivery");
      }
      ApsSystemUtils.getLogger().info("Newletter: delivery process completed");
    } catch (Throwable t) {
      ApsSystemUtils.getLogger().info("Newletter: delivery process ended abnormally");
      ApsSystemUtils.logThrowable(t, this, "sendNewsletterFromThread");
    } finally {
      this.setSendingNewsletter(false);
    }
  }
 
  @Override
  public String buildMailBody(Content content, boolean html) throws ApsSystemException {
    String mailBody = null;
    try {
      NewsletterConfig config = this.getConfig();
      NewsletterContentType contentType = config.getContentType(content.getTypeCode());
      int modelId = html ? contentType.getHtmlModel() : contentType.getSimpleTextModel();
      mailBody = this.buildMailBody(content, modelId, html);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "buildMailBody");
      throw new ApsSystemException("Errore in generazione body contenuto " + content.getId(), t);
    }
    return mailBody;
  }
 
  /**
   * Invia i contenuti dati agli utenti registrati alla newsletter discriminando, per ogni utente,
   * i contenuti a lui visibili e per i quali ha fatto implicita richiesta nel proprio profilo.
   * @param contents La lista dei contenuti da inviare tramite newsletter.
   * @throws ApsSystemException In caso di errore.
   */
  protected void sendNewsletterToUsers(List<Content> contents) throws ApsSystemException {
    try {
      Map<String, List<String>> profileAttributes = this.prepareProfileAttributesForContents(contents);
      NewsletterReport newsletterReport = this.prepareNewsletterReport(contents);
      Set<String> usernames = this.extractUsernames();
      if (null != usernames && usernames.size() > 0) {
        Iterator<String> userIter = usernames.iterator();
        while (userIter.hasNext()) {
          String username = (String) userIter.next();
          UserDetails user = this.getUserManager().getUser(username);
          if (null != user && !user.isDisabled()) {
            this.sendNewsletterToUser(username, contents, profileAttributes, newsletterReport);
          }
        }
      } else {
        ApsSystemUtils.getLogger().error("Newsletter: no receivers to send newsletter to!");
      }
      this.sendNewsletterToSubscribers(contents, newsletterReport);
      this.addNewsletterReport(newsletterReport);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "sendNewsletterToUsers");
      throw new ApsSystemException("Error sending Newsletter To Users ", t);
    }
  }
 
  /**
   * Salva il report della newsletter appena inviata.
   * @param newsletterReport Il report della newsletter.
   * @throws ApsSystemException In caso di errore.
   */
  protected void addNewsletterReport(NewsletterReport newsletterReport) throws ApsSystemException {
    if (null == newsletterReport) return;
    try {
      IKeyGeneratorManager keyGeneratorManager = this.getKeyGeneratorManager();
      newsletterReport.setId(keyGeneratorManager.getUniqueKeyCurrentValue());
      for (ContentReport contentReport : newsletterReport.getContentReports().values()) {
        contentReport.setId(keyGeneratorManager.getUniqueKeyCurrentValue());
      }
      this.getNewsletterDAO().addNewsletterReport(newsletterReport);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "buildMailBody", "Error adding newsletter report : id " + newsletterReport.getId());
    }
  }
 
  private Map<String, List<String>> prepareProfileAttributesForContents(List<Content> contents) {
    Map<String, List<String>> profileAttributes = new HashMap<String, List<String>>();
    Properties subscriptions = this.getConfig().getSubscriptions();
    for (int i=0; i<contents.size(); i++) {
      Content content = contents.get(i);
      List<String> contentProfileAttributes = this.extractProfileAttributesForContent(content, subscriptions);
      if (contentProfileAttributes != null && contentProfileAttributes.size() > 0) {
        profileAttributes.put(content.getId(), contentProfileAttributes);
      }
    }
    return profileAttributes;
  }
 
  protected NewsletterReport prepareNewsletterReport(List<Content> contents) {
    NewsletterConfig config = this.getConfig();
    NewsletterReport newsletterReport = new NewsletterReport();
    newsletterReport.setSubject(config.getSubject());
    newsletterReport.setSendDate(new Date());
    String defaultLang = this.getLangManager().getDefaultLang().getCode();
    boolean alsoHtml = config.isAlsoHtml();
    for (Content content : contents) {
      boolean isConfiguredWithModels = false;
      ContentReport contentReport = new ContentReport();
      contentReport.setContentId(content.getId());
      String textBodyPart = this.prepareMailBodyContentPart(content, defaultLang, false);
      if (null != textBodyPart) {
        isConfiguredWithModels = true;
        contentReport.setTextBody(textBodyPart);
      }
      if (alsoHtml) {
        String htmlBodyPart = this.prepareMailBodyContentPart(content, defaultLang, true);
        contentReport.setHtmlBody(htmlBodyPart);
      }
      if (isConfiguredWithModels) {
        newsletterReport.addContentReport(contentReport);
      } else {
        ApsSystemUtils.getLogger().info(" Newsletter content " + content.getId() + " not added, because has not model in config.");
      }
    }
    return newsletterReport;
  }
 
  private void sendNewsletterToUser(String username, List<Content> contents,
      Map<String, List<String>> profileAttributes, NewsletterReport newsletterReport) {
    NewsletterConfig config = this.getConfig();
    try {
      UserDetails user = this.getUserManager().getUser(username);
      IUserProfile profile = (IUserProfile) user.getProfile();
      if (profile != null) {
        String eMail = (String) profile.getValue(config.getMailAttrName());
        if (eMail != null && eMail.length() > 0) {
          List<Content> userContents = this.extractContentsForUser(user, eMail, contents, profileAttributes, newsletterReport);
          if (userContents.size() > 0) {
            String[] emailAddresses = { eMail };
            String simpleText = this.prepareMailBody(userContents, newsletterReport, false);
            if (config.isAlsoHtml()) {
              String htmlText = this.prepareMailBody(userContents, newsletterReport, true);
              this.getMailManager().sendMixedMail(simpleText, htmlText, config.getSubject(), null, null, null, emailAddresses, config.getSenderCode());
            } else {
              this.getMailManager().sendMail(simpleText, config.getSubject(), null, null, emailAddresses, config.getSenderCode());
            }
          }
        }
      }
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "sendNewsletterToUser");
    }
  }
 
  protected String prepareMailBody(List<Content> userContents, NewsletterReport newsletterReport, boolean isHtml) {
    StringBuffer body = this.prepareMailCommonBody(userContents, newsletterReport, isHtml);
    NewsletterConfig config = this.getConfig();
    body.append(isHtml ? config.getHtmlFooter() : config.getTextFooter());
    return body.toString();
  }
 
  protected StringBuffer prepareMailCommonBody(List<Content> userContents, NewsletterReport newsletterReport, boolean isHtml) {
    NewsletterConfig config = this.getConfig();
    StringBuffer body = new StringBuffer(isHtml ? config.getHtmlHeader() : config.getTextHeader());
    String separator = isHtml ? config.getHtmlSeparator() : config.getTextSeparator();
    boolean first = true;
    for (Content content : userContents) {
      ContentReport contentReport = newsletterReport.getContentReport(content.getId());
      if (contentReport != null) {
        if (first) {
          first = false;
        } else {
          body.append(separator);
        }
        String text = isHtml ? contentReport.getHtmlBody() : contentReport.getTextBody();
        body.append(text);
      }
    }
    return body;
  }
 
  /**
   * Prepara il body della mail in base al contenuto e al modello.
   * @param content Il Contenuto per cui costruire il body della mail.
   * @param modelId L'id del modello utilizzato.
   * @param html Indica se il modello è di tipo html o testo semplice.
   * @return Il body della mail completo di blocchi iniziale e finale.
   * @throws ApsSystemException
   */
  private String buildMailBody(Content content, long modelId, boolean html) throws ApsSystemException {
    NewsletterConfig config = this.getConfig();
    String header = html ? config.getHtmlHeader() : config.getTextHeader();
    String defaultLang = this.getLangManager().getDefaultLang().getCode();
    String mailContentBody = this.getContentRenderer().render(content, modelId, defaultLang, null);
    mailContentBody = this.getLinkResolver().resolveLinks(mailContentBody, null);
    String footer = html ? config.getHtmlFooter() : config.getTextFooter();
    String mailBody = header.concat(mailContentBody).concat(footer);
    if (!html) {
      return StringEscapeUtils.unescapeHtml(mailBody);
    }
    return mailBody;
  }
 
  /**
   * Estrae gli username dei destinatari della newsletter.
   * @return Il set contenente gli username dei destinatari della newsletter.
   * @throws ApsSystemException
   */
  private Set<String> extractUsernames() throws ApsSystemException {
    NewsletterConfig config = this.getConfig();
    Set<String> usernames = new HashSet<String>();
    String allContentsAttribute = config.getAllContentsAttributeName();
    if (null != allContentsAttribute && allContentsAttribute.trim().length() > 0) {
      EntitySearchFilter filter = new EntitySearchFilter(allContentsAttribute, true, new Boolean(true), false);
      EntitySearchFilter[] filters = {filter};
      try {
        List<String> usernamesForAllContents = ((IEntityManager) this.getProfileManager()).searchId(filters);
        usernames.addAll(usernamesForAllContents);
      } catch (Throwable t) {
        ApsSystemUtils.logThrowable(t, this, "extractUsernames");
        throw new ApsSystemException("Error searching for usernames on profile's attribute " + allContentsAttribute, t);
      }
    }
    Iterator<Object> subscriptionsIter = config.getSubscriptions().values().iterator();
    while (subscriptionsIter.hasNext()) {
      String boolAttributeName = (String) subscriptionsIter.next();
      if (null != boolAttributeName && boolAttributeName.trim().length() > 0) {
        EntitySearchFilter filter = new EntitySearchFilter(boolAttributeName, true, new Boolean(true), false);
        EntitySearchFilter[] filters = {filter};
        try {
          List<String> usernamesForCategory = ((IEntityManager) this.getProfileManager()).searchId(filters);
          usernames.addAll(usernamesForCategory);
        } catch (Throwable t) {
          ApsSystemUtils.logThrowable(t, this, "extractUsernames");
          throw new ApsSystemException("Error searching for usernames on profile's attribute " + boolAttributeName, t);
        }
      }
    }
    return usernames;
  }
 
  private List<Content> extractContentsForUser(UserDetails user, String eMail, List<Content> contents,
      Map<String, List<String>> profileAttributes, NewsletterReport newsletterReport) throws ApsSystemException {
    NewsletterConfig config = this.getConfig();
    List<Content> userContents = new ArrayList<Content>();
    String username = user.getUsername();
    IUserProfile profile = (IUserProfile) user.getProfile();
    if (profile != null) {
      String allContentsAttribute = config.getAllContentsAttributeName();
      boolean allContents = false;
      if (null != allContentsAttribute) {
        Boolean value = (Boolean) profile.getValue(allContentsAttribute);
        allContents = value != null && value.booleanValue();
      }
      List<String> groupNames = this.extractUserGroupNames(user);
      boolean isGroupAdmin = groupNames.contains(Group.ADMINS_GROUP_NAME);
      for (int i=0; i<contents.size(); i++) {
        Content content = contents.get(i);
        String contentId = content.getId();
        List<String> contentProfileAttributes = profileAttributes.get(contentId);
        ContentReport contentReport = newsletterReport.getContentReport(contentId);
        if (contentReport != null && (isGroupAdmin || this.checkUserAllowedOnContent(groupNames, content))) {
          if (allContents) {
            userContents.add(content);
            contentReport.addRecipient(username, eMail);
          } else if (contentProfileAttributes!=null && contentProfileAttributes.size() > 0) {
            for (String profileAttrName : contentProfileAttributes) {
              Boolean value = (Boolean) profile.getValue(profileAttrName);
              if (value != null && value.booleanValue()) {
                userContents.add(content);
                contentReport.addRecipient(username, eMail);
                break;
              }
            }
          }
        }
      }
    }
    return userContents;
  }
 
  private List<String> extractProfileAttributesForContent(Content content, Properties subscriptions) {
    Collection<String> categories = this.extractCategoryCodes(content);
    List<String> profileAttributes = new ArrayList<String>();
    for (String categoryCode : categories) {
      String attributeName = subscriptions.getProperty(categoryCode);
      if (attributeName != null) {
        profileAttributes.add(attributeName);
      }
    }
    return profileAttributes;
  }
 
  private String prepareMailBodyContentPart(Content content, String defaultLang, boolean isHtml) {
    NewsletterContentType contentType = this.getConfig().getContentTypes().get(content.getTypeCode());
    int modelId = isHtml ? contentType.getHtmlModel() : contentType.getSimpleTextModel();
    String mailContentBody = this.getContentRenderer().render(content, modelId, defaultLang, null);
    mailContentBody = this.getLinkResolver().resolveLinks(mailContentBody, null);
    if (!isHtml) {
      return StringEscapeUtils.unescapeHtml(mailContentBody);
    }
    return mailContentBody;
  }
 
  private List<String> extractUserGroupNames(UserDetails user) throws ApsSystemException {
    List<IApsAuthority> authorities = this.getGroupManager().getAuthorizationsByUser(user);
    List<String> groupNames = new ArrayList<String>(authorities.size());
    for (IApsAuthority authority : authorities) {
      groupNames.add(authority.getAuthority());
    }
    return groupNames;
  }
 
  private boolean checkUserAllowedOnContent(List<String> userGroups, Content content) {
    String mainGroup = content.getMainGroup();
    boolean allowed = false;
    if (Group.FREE_GROUP_NAME.equals(mainGroup) || userGroups.contains(mainGroup)) {
      allowed = true;
    } else if (!this.getConfig().isOnlyOwner()) {
      for (String current : content.getGroups()) {
        if (Group.FREE_GROUP_NAME.equals(current) || userGroups.contains(current)) {
          allowed = true;
          break;
        }
      }
    }
    return allowed;
  }
 
  /**
   * Estrae i codici delle categorie della newsletter
   * @param content Il contenuto a cui si riferisce la newsletter.
   * @return Il set contenente i codici delle categorie della newsletter come {@link String}.
   */
  private Set<String> extractCategoryCodes(Content content) {
    Set<String> categoryCodes = new HashSet<String>();
    Iterator<Category> categoryIter = content.getCategories().iterator();
    while (categoryIter.hasNext()) {
      Category category = categoryIter.next();
      this.addCategoryCode(category, categoryCodes);
    }
    return categoryCodes;
  }
 
  /**
   * Aggiunge al {@link Set} dei codici il codice della categoria data.
   * @param category La categoria da aggiungere.
   * @param codes Il {@link Set} dei codici delle categorie.
   */
  private void addCategoryCode(Category category, Set<String> codes) {
    codes.add(category.getCode());
    Category parentCategory = (Category) category.getParent();
    if (null != parentCategory && !parentCategory.getCode().equals(parentCategory.getParentCode())) {
      this.addCategoryCode(parentCategory, codes);
    }
  }
 
  @Override
  public List<String> loadNewsletterContentIds(EntitySearchFilter[] filters,
      Collection<String> userGroupCodes, NewsletterSearchBean searchBean) throws ApsSystemException {
    List<String> contentsId = null;
    try {
      NewsletterConfig config = this.getConfig();
      String[] contentTypes = config.getContentTypesArray();
      if (contentTypes==null || contentTypes.length==0) {
        contentsId = new ArrayList<String>();
      } else {
        String[] categories = (null != config.getAllContentsAttributeName()) ? null : config.getCategoriesArray();
        contentsId = this.getNewsletterSearcherDAO().loadNewsletterContentsId(contentTypes,
            categories, filters, userGroupCodes);
        Boolean inQueue = searchBean.getInQueue();
        if (inQueue!=null) {
          List<String> contentQueue = this.getNewsletterDAO().loadContentQueue();
          if (inQueue.booleanValue()) {
            contentsId = this.intersectContentIds(contentsId, contentQueue);
          } else {
            contentsId = this.exceptContentIds(contentsId, contentQueue);
          }
        }
        Boolean sent = searchBean.getSent();
        if (sent!=null) {
          List<String> sentContentIds = this.getNewsletterDAO().loadSentContentIds();
          if (sent.booleanValue()) {
            contentsId = this.intersectContentIds(contentsId, sentContentIds);
          } else {
            contentsId = this.exceptContentIds(contentsId, sentContentIds);
          }
        }
      }
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "loadNewsletterContentsId",
          "Errore spedizione lista contenuti newsletter ");
    }
    return contentsId;
  }
 
  private List<String> exceptContentIds(List<String> contentIds, List<String> exceptedContentIds) {
    if (exceptedContentIds.size()>0 && contentIds.size()>0) {
      for (String contentId : exceptedContentIds) {
        contentIds.remove(contentId);
        if (contentIds.size()==0) {
          break;
        }
      }
    }
    return contentIds;
  }
 
  protected List<String> intersectContentIds(List<String> contentIds, List<String> intersectedContentIds) {
    List<String> intersection = new ArrayList<String>();
    if (intersectedContentIds.size()>0 && contentIds.size()>0) {
      for (String contentId : intersectedContentIds) {
        if (contentIds.remove(contentId)) {
          intersection.add(contentId);
        }
      }
    }
    return intersection;
  }
 
 
  @Override
  public List<Subscriber> loadSubscribers() throws ApsSystemException {
    List<Subscriber> subscribers = new ArrayList<Subscriber>();
    try {
      subscribers = this.getNewsletterDAO().loadSubscribers();
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "loadSubscribers");
      throw new ApsSystemException(
          "Errore caricamento di tutte le sottoscrizioni", t);
    }
    return subscribers;
  }
 
  @Override
  public List<Subscriber> searchSubscribers(String mailAddress, Boolean active) throws ApsSystemException {
    List<Subscriber> subscribers = new ArrayList<Subscriber>();
    try {
      subscribers = this.getNewsletterDAO().searchSubscribers(mailAddress, active);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "searchSubscribers");
      throw new ApsSystemException("Errore in ricerca sottoscrizioni", t);
    }
    return subscribers;
  }
 
  @Override
  public Subscriber loadSubscriber(String mailAddress) throws ApsSystemException {
    try {
      this.cleanOldSubscribers();
      Subscriber subscriber = this.getNewsletterDAO().loadSubscriber(mailAddress);
      return subscriber;
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "loadSubscriber");
      throw new ApsSystemException("Errore caricamento di un sottoscrizioni " + mailAddress, t);
    }
  }
 
  @Override
  public void addSubscriber(String mailAddress) throws ApsSystemException {
    try {
      Subscriber subscriber = new Subscriber();
      subscriber.setMailAddress(mailAddress);
      subscriber.setSubscriptionDate(new Date());
      subscriber.setActive(false);
      String token = this.createToken(mailAddress);
      this.getNewsletterDAO().addSubscriber(subscriber, token);
      this.sendSubscriptionMail(mailAddress, token);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "addSubscriber");
      throw new ApsSystemException("Errore in aggiunta sottoscrizione", t);
    }
  }
 
  @Override
  public void resetSubscriber(String mailAddress) throws ApsSystemException {
    try {
      Subscriber subscriber = new Subscriber();
      subscriber.setMailAddress(mailAddress);
      subscriber.setSubscriptionDate(new Date());
      subscriber.setActive(false);
      String token = this.createToken(mailAddress);
      this.getNewsletterDAO().updateSubscriber(subscriber, token);
      this.sendSubscriptionMail(mailAddress, token);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "resetSubscriber");
      throw new ApsSystemException("Errore in reset sottoscrizione", t);
    }
  }
 
  @Override
  public void deleteSubscriber(String mailAddress) throws ApsSystemException {
    try {
      this.getNewsletterDAO().deleteSubscriber(mailAddress);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "deleteSubscriber");
      throw new ApsSystemException("Errore cancellazione sottoscrizione", t);
    }
  }
 
  @Override
  public void activateSubscriber(String mailAddress, String token) throws ApsSystemException {
    try {
      this.cleanOldSubscribers();
      this.getNewsletterDAO().activateSubscriber(mailAddress);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "activateSubscriber");
      throw new ApsSystemException("Errore attivazione sottoscrizione", t);
    }
  }
 
  @Override
  public String getAddressFromToken(String token) throws ApsSystemException {
    try {
      String mailAddress = this.getNewsletterDAO().getAddressFromToken(token);
      return mailAddress;
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "getAddressFromToken");
      throw new ApsSystemException("Error loading address from token", t);
    }
  }
 
  @Override
  public void cleanOldSubscribers() throws ApsSystemException {
    int days = this.getConfig().getSubscriptionTokenValidityDays();
    long time = new Date().getTime() - (86400000l * days);
    Date expiration = new Date(time);
    this.getNewsletterDAO().cleanOldSubscribers(expiration);
  }
 
  @Override
  public Boolean isAlreadyAnUser(String mailAddress) throws ApsSystemException {
    List<String> usernames = null;
    try {
      String emailAttributeName = this.getConfig().getMailAttrName();
      EntitySearchFilter filterByEmail = new EntitySearchFilter(emailAttributeName, true, mailAddress, true);
      EntitySearchFilter[] filters = {filterByEmail};
      usernames = ((IEntityManager) this.getProfileManager()).searchId(filters);
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "isAlreadyAnUser");
      throw new ApsSystemException("Errore ricerca indirizzo e-mail tra gli utenti registrati", t);
    }
    return (null != usernames && usernames.size() > 0);
  }
 
  /**
   * Generated random token
   */
  protected String createToken(String word) throws NoSuchAlgorithmException {
    Random random = new Random();
    StringBuilder salt = new StringBuilder();
    long rndLong = random.nextLong();
    salt.append(rndLong);
    String date = DateConverter.getFormattedDate(new Date(), "SSSmmyyyy-SSS-MM:ssddmmHHmmEEE");
    salt.append(date);
    rndLong = random.nextLong();
    salt.append(rndLong);
    // genero il token in base a username e salt
    String token = ShaEncoder.encodeWord(word, salt.toString());
    return token;
  }
 
  protected void sendSubscriptionMail(String mailAddress, String token) throws ApsSystemException {
    try {
      EmailSenderThread thread = new EmailSenderThread(mailAddress, token, this);
      thread.setName(JpnewsletterSystemConstants.EMAIL_SENDER_NAME_THREAD_PREFIX + System.currentTimeMillis());
      thread.start();
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "sendMail");
      throw new ApsSystemException("errore in invio email", t);
    }
  }
 
  /**
   * Create link for email confirmation
   * */
  protected String createLink(String mailAddress, String token) {
    NewsletterConfig config = this.getConfig();
    String langcode = this.getLangManager().getDefaultLang().getCode();
    String pageCode = config.getSubscriptionPageCode();
    String applBaseUrl = this.getConfigManager().getParam(SystemConstants.PAR_APPL_BASE_URL);
    StringBuffer link = new StringBuffer(applBaseUrl);
    link.append(langcode);
    link.append("/");
    link.append(pageCode);
    link.append(".wp");
    link.append("?mailAddress=");
    link.append(mailAddress);
    link.append("&token=");
    link.append(token);
    return link.toString();
  }
 
  protected String parseText(String defaultText, Map<String, String> params) {
    String body = defaultText;
    for (Entry<String, String> pairs : params.entrySet()) {
      String regExp = "\\{" + pairs.getKey() + "\\}";
      Pattern pattern = Pattern.compile(regExp);
      Matcher codeMatcher = pattern.matcher("");
      codeMatcher.reset(body);
      if (codeMatcher.find()) {
        body = codeMatcher.replaceAll((String) pairs.getValue());
      }
    }
    return body;
  }
 
  protected void sendSubscriptionFormThread(String mailAddress, String token) throws ApsSystemException {
    try {
      NewsletterConfig config = this.getConfig();
     
      String senderCode = config.getSenderCode();
      String subject = config.getSubscriptionSubject();
      if (subject!=null) {
        Map<String, String> bodyParams = new HashMap<String, String>();
        String link = this.createLink(mailAddress, token);
        bodyParams.put("subscribeLink", link);
        String textBody = this.parseText(config.getSubscriptionTextBody(), bodyParams);
        String[] recipientsTo = new String[] { mailAddress };
        if (config.isAlsoHtml()) {
          String htmlBody = this.parseText(config.getSubscriptionHtmlBody(), bodyParams);
          this.getMailManager().sendMixedMail(textBody, htmlBody, subject, null, recipientsTo, null, null, senderCode);
        } else {
          this.getMailManager().sendMail(textBody, subject, recipientsTo, null, null, senderCode, IMailManager.CONTENTTYPE_TEXT_PLAIN);
        }
      } else {
        ApsSystemUtils.getLogger().warn("Incomplete configuration for newsletter subscribers! CHECK " + JpnewsletterSystemConstants.NEWSLETTER_CONFIG_ITEM + " item!!");
      }
    } catch (Throwable t) {
      ApsSystemUtils.logThrowable(t, this, "sendMail");
      throw new ApsSystemException("Error sending email for subscription confirmation request to address " + mailAddress, t);
    }
  }
 
  private void sendNewsletterToSubscribers(List<Content> contents, NewsletterReport newsletterReport) throws ApsSystemException {
    List<Content> contentsToSubscribers = new ArrayList<Content>();
    for (int i = 0; i < contents.size(); i++) {
      Content content = contents.get(i);
      if (this.isContentToSend(content)) {
        contentsToSubscribers.add(content);
      }
    }
    this.sendContentsToSubscribers(contentsToSubscribers, newsletterReport);
  }
 
  private boolean isContentToSend(Content content) {
    if (null == content) return false;
    String mainGroup = content.getMainGroup();
    if (null != mainGroup && Group.FREE_GROUP_NAME.equals(mainGroup)) return true;
    Set<String> groups = content.getGroups();
    if (null != groups && groups.contains(Group.FREE_GROUP_NAME)) {
      return true;
    }
    return false;
  }
 
  private void sendContentsToSubscribers(List<Content> contents, NewsletterReport newsletterReport) throws ApsSystemException {
    List<Subscriber> subscribers = this.searchSubscribers(null, new Boolean(true));
    NewsletterConfig config = this.getConfig();
    for (Subscriber subscriber : subscribers) {
      String mailAddress = subscriber.getMailAddress();
      String[] emailAddresses = { mailAddress };
      String simpleText = this.prepareSubscribersMailBody(contents, newsletterReport, false, mailAddress);
      if (config.isAlsoHtml()) {
        String htmlText = this.prepareSubscribersMailBody(contents, newsletterReport, true, mailAddress);
        this.getMailManager().sendMixedMail(simpleText, htmlText, config.getSubject(), null, null, null, emailAddresses, config.getSenderCode());
      } else {
        this.getMailManager().sendMail(simpleText, config.getSubject(), null, null, emailAddresses, config.getSenderCode());
      }
    }
  }
 
  private String prepareSubscribersMailBody(List<Content> userContents, NewsletterReport newsletterReport, boolean isHtml, String mailAddress) {
    NewsletterConfig config = this.getConfig();
    String unsubscriptionLink = isHtml ? config.getSubscribersHtmlFooter() : config.getSubscribersTextFooter();
    if (unsubscriptionLink!=null) {
      StringBuffer body = this.prepareMailCommonBody(userContents, newsletterReport, isHtml);
      String link = this.createUnsubscriptionLink(mailAddress);
      Map<String, String> footerParams = new HashMap<String, String>();
      footerParams.put("unsubscribeLink", link);
      String unlink = this.parseText(unsubscriptionLink, footerParams);
      body.append(unlink);
      return body.toString();
    } else {
      ApsSystemUtils.getLogger().warn("Incomplete configuration for newsletter subscribers! CHECK " + JpnewsletterSystemConstants.NEWSLETTER_CONFIG_ITEM + " item!!");
      return this.prepareMailBody(userContents, newsletterReport, isHtml);
    }
  }
 
  /**
   * Create link for newsletter unsubscription
   * */
  protected String createUnsubscriptionLink(String mailAddress) {
    NewsletterConfig config = this.getConfig();
    String langcode = this.getLangManager().getDefaultLang().getCode();
    String pageCode = config.getUnsubscriptionPageCode();
    String applBaseUrl = this.getConfigManager().getParam(SystemConstants.PAR_APPL_BASE_URL);
    StringBuffer link = new StringBuffer(applBaseUrl);
    link.append(langcode);
    link.append("/");
    link.append(pageCode);
    link.append(".wp");
    link.append("?mailAddress=");
    link.append(mailAddress);
    return link.toString();
  }
 
  protected boolean isSendingNewsletter() {
    return _sendingNewsletter;
  }
  protected void setSendingNewsletter(boolean sendingNewsletter) {
    this._sendingNewsletter = sendingNewsletter;
  }
 
  protected NewsletterConfig getConfig() {
    return this._config;
  }
  protected void setConfig(NewsletterConfig config) {
    this._config = config;
  }
 
  @Override
  public String[] getSenderCodes() {
    return new String[] { this.getConfig().getSenderCode() };
  }
 
  protected IMailManager getMailManager() {
    return _mailManager;
  }
  public void setMailManager(IMailManager mailManager) {
    this._mailManager = mailManager;
  }
 
  protected IUserManager getUserManager() {
    return _userManager;
  }
  public void setUserManager(IUserManager userManager) {
    this._userManager = userManager;
  }
 
  protected IContentManager getContentManager() {
    return _contentManager;
  }
  public void setContentManager(IContentManager contentManager) {
    this._contentManager = contentManager;
  }
 
  public IApsAuthorityManager getGroupManager() {
    return _groupManager;
  }
  public void setGroupManager(IApsAuthorityManager groupManager) {
    this._groupManager = groupManager;
  }
 
  protected IUserProfileManager getProfileManager() {
    return _profileManager;
  }
  public void setProfileManager(IUserProfileManager profileManager) {
    this._profileManager = profileManager;
  }
 
  protected ILinkResolverManager getLinkResolver() {
    return _linkResolver;
  }
  public void setLinkResolver(ILinkResolverManager linkResolver) {
    this._linkResolver = linkResolver;
  }
 
  protected ILangManager getLangManager() {
    return _langManager;
  }
  public void setLangManager(ILangManager langManager) {
    this._langManager = langManager;
  }
 
  protected IContentRenderer getContentRenderer() {
    return _contentRenderer;
  }
  public void setContentRenderer(IContentRenderer renderer) {
    this._contentRenderer = renderer;
  }
 
  /**
   * Returns the configuration manager.
   * @return The Configuration manager.
   */
  protected ConfigInterface getConfigManager() {
    return _configManager;
  }
  /**
   * Set method for Spring bean injection.<br /> Set the Configuration manager.
   * @param configManager The Configuration manager.
   */
  public void setConfigManager(ConfigInterface configManager) {
    this._configManager = configManager;
  }
 
  protected IKeyGeneratorManager getKeyGeneratorManager() {
    return _keyGeneratorManager;
  }
  public void setKeyGeneratorManager(IKeyGeneratorManager keyGeneratorManager) {
    this._keyGeneratorManager = keyGeneratorManager;
  }
 
  protected INewsletterDAO getNewsletterDAO() {
    return _newsletterDAO;
  }
  public void setNewsletterDAO(INewsletterDAO newsletterDAO) {
    this._newsletterDAO = newsletterDAO;
  }
 
  protected INewsletterSearcherDAO getNewsletterSearcherDAO() {
    return _newsletterSearcherDAO;
  }
  public void setNewsletterSearcherDAO(INewsletterSearcherDAO newsletterSearcherDAO) {
    this._newsletterSearcherDAO = newsletterSearcherDAO;
  }
 
  private NewsletterConfig _config;
  private boolean _sendingNewsletter = false;
 
  private IMailManager _mailManager;
  private IUserProfileManager _profileManager;
  private IUserManager _userManager;
  private IContentManager _contentManager;
  private IApsAuthorityManager _groupManager;
  private ILinkResolverManager _linkResolver;
  private ILangManager _langManager;
  private IContentRenderer _contentRenderer;
  private ConfigInterface _configManager;
  private INewsletterDAO _newsletterDAO;
  private INewsletterSearcherDAO _newsletterSearcherDAO;
  private IKeyGeneratorManager _keyGeneratorManager;
 
  private TimerTask _scheduler;
 
}
TOP

Related Classes of com.agiletec.plugins.jpnewsletter.aps.system.services.newsletter.NewsletterManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.