NotificationEngine.java :  » JBoss » jboss-forums » org » jboss » portlet » forums » util » Java Open Source

Java Open Source » JBoss » jboss forums 
jboss forums » org » jboss » portlet » forums » util » NotificationEngine.java
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.portlet.forums.util;

import java.io.StringWriter;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;

import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.mail.Address;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.Message.RecipientType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.portlet.ActionResponse;
import javax.rmi.PortableRemoteObject;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.apache.log4j.Logger;
import org.jboss.portal.common.transaction.Transactions;
import org.jboss.portal.format.render.bbcodehtml.ToTextRenderer;
import org.jboss.portal.format.template.TemplateLoader;
import org.jboss.portal.identity.IdentityException;
import org.jboss.portal.identity.User;
import org.jboss.portal.identity.UserProfileModule;
import org.jboss.portlet.forums.ForumsConstants;
import org.jboss.portlet.forums.ForumsModule;
import org.jboss.portlet.forums.auth.Authorization;
import org.jboss.portlet.forums.auth.AuthorizationInterface;
import org.jboss.portlet.forums.auth.JSFUIContext;
import org.jboss.portlet.forums.model.Category;
import org.jboss.portlet.forums.model.Forum;
import org.jboss.portlet.forums.model.Message;
import org.jboss.portlet.forums.model.Post;
import org.jboss.portlet.forums.model.Topic;
import org.jboss.portlet.forums.model.TopicWatch;
import org.jboss.portlet.forums.model.Watch;
import org.jboss.portlet.forums.ui.Constants;
import org.jboss.portlet.forums.ui.PortalUtil;

import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
import EDU.oswego.cs.dl.util.concurrent.QueuedExecutor;

/**
 * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
 * @author <a href="mailto:ryszard.kozmik@jboss.com">Ryszard Kozmik</a>
 */
public class NotificationEngine
{
   // Types of post
   public static final int MODE_POST = 0;
   public static final int MODE_REPLY = 1;
   public static final int MODE_REPOST = 2;

   private ForumsModule forumsModule;
   private UserProfileModule userProfileModule;
   private TemplateLoader mailTemplates;
   private String from;
   private QueuedExecutor executor;
   private TransactionManager tm;
   private final Logger log = Logger.getLogger(NotificationEngine.class);

   public NotificationEngine(ForumsModule module)
   {
      try
      {
         this.forumsModule = module;
         InitialContext ctx = new InitialContext();
         tm = (TransactionManager)ctx.lookup("java:TransactionManager");
         executor = new QueuedExecutor(new LinkedQueue());
         userProfileModule = forumsModule.getUserProfileModule();
      }
      catch (NamingException e)
      {
         log.error("Cannot create notification interceptor", e);
      }
   }

   public void stop()
   {
      executor.shutdownAfterProcessingCurrentTask();
      executor = null;
      forumsModule = null;
      tm = null;
   }

   public void setFrom(String from)
   {
      this.from = from;
   }

   public TemplateLoader getMailTemplates()
   {
      return mailTemplates;
   }
   
   public void scheduleForNotification(Integer postId, int mode) {
       Object responseObj = FacesContext.getCurrentInstance().getExternalContext().getResponse();
       
       if (responseObj instanceof ActionResponse) {
           
           ActionResponse response = (ActionResponse)responseObj;
           response.setRenderParameter(Constants.p_notified_post_id, postId.toString());
           response.setRenderParameter(Constants.p_notified_watch_type, Integer.toString(mode));
           
       } else {
           // TODO: IMPLEMENT NOTIFICATION FOR STANDALONE VERSION OF FORUMS.
           log.warn("NOTIFICATION FOR STANDALONE HAS NOT BEEN YET IMPLEMENTED");
       }
       
   }

   public void schedule(Integer postId, int mode, String absViewURL , String absReplyURL )
   {
      try
      {
         
          if (postId==null || mode == -1) {
              log.warn("Request didn't have needed parameters.");
              return;
          }
          
         // Getting ResourceBundle with current Locale
         // Too bad for now we support notifications sent in the locale of the poster :-(
         
         FacesContext ctx = FacesContext.getCurrentInstance();
         UIViewRoot uiRoot = ctx.getViewRoot();
         Locale locale = uiRoot.getLocale();
         ClassLoader ldr = Thread.currentThread().getContextClassLoader();
         ResourceBundle bundle = ResourceBundle.getBundle("ResourceJSF",locale,ldr);

         // Getting Authorization realm
         AuthorizationInterface realm = Authorization.getProvider();
         
         // Create task
         NotificationTask task = new NotificationTask(tm, absViewURL, absReplyURL ,
                 postId, mode, bundle , realm );

         //Register at the end of the current tx to broadcast notifications
         Transaction tx = tm.getTransaction();
         tx.registerSynchronization(task);
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }

   private String getFrom(Post post)
   { 
       StringBuffer fromBuf = null;
       try {
          if ( (userProfileModule.getProperty(post.getPoster().getUser(),User.INFO_USER_NAME_GIVEN) != null)
             && (userProfileModule.getProperty(post.getPoster().getUser(),User.INFO_USER_NAME_FAMILY) != null))
          {
             fromBuf = new StringBuffer(userProfileModule.getProperty(post.getPoster().getUser(),User.INFO_USER_NAME_GIVEN)
                + " " + userProfileModule.getProperty(post.getPoster().getUser(),User.INFO_USER_NAME_FAMILY) + " <");
          }
          else
          {
             fromBuf = new StringBuffer(post.getPoster().getUser().getUserName() + " <");
          }
      fromBuf.append(from + ">");
       } catch (IdentityException e) {
           log.error(e);
       }
      return fromBuf.toString();
   }

   /**
    * The notification task.
    */
   class NotificationTask implements Transactions.Runnable, Synchronization
   {

      private final TransactionManager tm;
      private final int mode;
      private final Integer postId;
      private final ResourceBundle bundle;
      private final String viewURL;
      private final String replyURL;
      private final AuthorizationInterface realm;

      NotificationTask(TransactionManager tm, String viewURL, String replyURL,
              final Integer postId, int mode, ResourceBundle bundle , AuthorizationInterface realm)
      {
         this.tm = tm;
         this.mode = mode;
         this.postId = postId;
         this.viewURL = viewURL;
         this.replyURL = replyURL;
         this.bundle = bundle;
         this.realm = realm;
      }

      public Object run() throws Exception
      {
         try
         {
            Post post = forumsModule.findPostById(postId);
            Topic topic = post.getTopic();
            Forum forum = topic.getForum();
            Category category = forum.getCategory();
            
            Message message = post.getMessage();
            String from = getFrom(post);
            // Hold the notified users to avoid duplicated
            Set notifieds = new HashSet();

            // If this is not an anonymous post, put the user in the notified list
            // he won't be notified of his own action
            User poster = post.getPoster().getUser();
            if (poster != null)
            {
               notifieds.add(poster.getId());
            }

            char[] chars = message.getText().toCharArray();
            StringWriter out = new StringWriter();
            ToTextRenderer renderer = new ToTextRenderer();
            renderer.setWriter(out);
            renderer.render(chars, 0, chars.length);
            
            String forumEmbededArgsSubject = "[" + forum.getName() + "] - "
               + message.getSubject()
               + (mode == MODE_REPOST ? " (Repost)" : "");
            
            String forumEmbededArgsText = out.toString() + "<br /><br />\n"
               + bundle.getString("EMAIL_VIEWORIGINAL") + " : "
               + "<a href=\""+viewURL.toString() + "\">" + viewURL.toString() + "</a>\n"
               + "<br /><br />\n"
               + bundle.getString("EMAIL_REPLY") + " : "
               + "<a href=\""+replyURL.toString() + "\">" + replyURL.toString() + "</a>"
               + "<br /><br />\n";
            
            // For now it is just a copy from embeded mode maybe in future we will differentiate it.
            String forumLinkedArgsSubject = forumEmbededArgsSubject;
            
            String forumLinkedArgsText = bundle.getString("EMAIL_LINKED_MODE_INFO")+" <b>"+forum.getName()+"</b> <br /><br />\n"
                + bundle.getString("EMAIL_VIEWORIGINAL") + " : "
                + "<a href=\""+viewURL.toString() + "\">" + viewURL.toString() + "</a>\n"
                + "<br /><br />\n"
                + bundle.getString("EMAIL_REPLY") + " : "
                + "<a href=\""+replyURL.toString() + "\">" + replyURL.toString() + "</a>"
                + "<br /><br />\n";
            
            // Notify the forum watchers
            for (Iterator i = forum.getWatches().iterator(); i.hasNext();)
            {
               try
               {
                  Watch watch = (Watch)i.next();
                  
                  // If user don't want to be notified by e-mail then continue with next watch.
                  if (watch.getMode()==ForumsConstants.WATCH_MODE_NONE)
                  {
                      continue;
                  }
                  
                  User watcher = watch.getPoster().getUser();
                  Object watcherId = watcher.getId();
                  
                  if (!notifieds.contains(watcherId) && !watcherId.equals(PortalUtil.getUserNA().getId()))
                  {
                     
                     boolean securityFlag = true;
                      
                     // Creating security context for the user
                     JSFUIContext securityContext = new JSFUIContext(watcher,FacesContext.getCurrentInstance());
                     
                     // Checking if user has privileges to read category
                     securityContext.setFragment("acl://readCategory");
                     securityContext.setContextData(new Object[]{category});
                     securityFlag = realm.hasAccess(securityContext) && securityFlag;
                     
                     // Checking if user has privileges to read forum
                     securityContext.setFragment("acl://readForum");
                     securityContext.setContextData(new Object[]{forum});
                     securityFlag = realm.hasAccess(securityContext) && securityFlag;
                     
                     if (securityFlag)
                     {
                        notifieds.add(watcherId);
                        String subject = null;
                        String text = null;
                        
                        if (watch.getMode() == ForumsConstants.WATCH_MODE_EMBEDED)
                        {
                            subject = forumEmbededArgsSubject;
                            text = forumEmbededArgsText; 
                        }
                        else if (watch.getMode()==ForumsConstants.WATCH_MODE_LINKED)
                        {
                           subject = forumLinkedArgsSubject;
                           text = forumLinkedArgsText;
                        }
                        
                        notify ( watcher, from , subject, text );

                     }
                     else
                     {
                        // Not authorized anymore, we remove the watch
                        forumsModule.removeWatch(watch);
                     }
                  }
               }
               catch (Exception e)
               {
                  log.error("Cannot send an email notification", e);
               }
            }
            
            
            String topicEmbededArgsSubject = "[" + forum.getName() + "] - "
                + message.getSubject()
                + (mode == MODE_REPOST ? " (Repost)" : "");
            
            String topicEmbededArgsText = out.toString() + "<br /><br />\n"
                + bundle.getString("EMAIL_VIEWORIGINAL") + " : "
                + "<a href=\""+viewURL.toString() + "\">" + viewURL.toString() + "</a>\n"
                + "<br /><br />\n"
                + bundle.getString("EMAIL_REPLY") + " : "
                + "<a href=\""+replyURL.toString() + "\">" + replyURL.toString() + "</a>"
                + "<br /><br />\n";
             
            // For now it is just a copy from embeded mode maybe in future we will differentiate it.
            String topicLinkedArgsSubject = topicEmbededArgsSubject;
             
            String topicLinkedArgsText = bundle.getString("EMAIL_LINKED_MODE_INFO")+": <b>"+topic.getSubject()+"</b><br /><br />\n"
                + bundle.getString("EMAIL_VIEWORIGINAL") + " : "
                + "<a href=\""+viewURL.toString() + "\">" + viewURL.toString() + "</a>\n"
                + "<br /><br />\n"
                + bundle.getString("EMAIL_REPLY") + " : "
                + "<a href=\""+replyURL.toString() + "\">" + replyURL.toString() + "</a>"
                + "<br /><br />\n";
            
            // Notify the topic watchers
            if (mode == MODE_REPLY)
            {
                // Notify the reply watchers
                for (Iterator i = topic.getWatches().iterator(); i.hasNext();)
                {
                   try
                   {
                      TopicWatch watch = (TopicWatch)i.next();
                      
                      // If user don't want to be notified by e-mail then continue with next watch.
                      if (watch.getMode()==ForumsConstants.WATCH_MODE_NONE)
                      {
                          continue;
                      }
                      
                      User watcher = watch.getPoster().getUser();
                      Object watcherId = watcher.getId();
                      if (!notifieds.contains(watcherId) && !watcherId.equals(PortalUtil.getUserNA().getId()))
                      {
                          boolean securityFlag = true;
                          
                          // Creating security context for the user
                          JSFUIContext securityContext = new JSFUIContext(watcher,FacesContext.getCurrentInstance());
                          
                          // Checking if user has privileges to read category
                          securityContext.setFragment("acl://readCategory");
                          securityContext.setContextData(new Object[]{category});
                          securityFlag = realm.hasAccess(securityContext) && securityFlag;
                          
                          // Checking if user has privileges to read forum
                          securityContext.setFragment("acl://readForum");
                          securityContext.setContextData(new Object[]{forum});
                          securityFlag = realm.hasAccess(securityContext) && securityFlag;
                          
                          if (securityFlag)
                          {
                              // Authorized
                              notifieds.add(watcherId);
                              String subject = null;
                              String text = null;
                              
                              if (watch.getMode() == ForumsConstants.WATCH_MODE_EMBEDED)
                              {
                                  subject = topicEmbededArgsSubject;
                                  text = topicEmbededArgsText; 
                              }
                              else if (watch.getMode()==ForumsConstants.WATCH_MODE_LINKED)
                              {
                                 subject = topicLinkedArgsSubject;
                                 text = topicLinkedArgsText;
                              }
                              
                              notify( watcher, from , subject , text );
                          }
                          else
                          {
                              // Not authorized anymore, we remove the watch
                              forumsModule.removeWatch(watch);
                          }
                       }
                   }
                   catch (Exception e)
                   {
                      log.error("Cannot send email notification", e);
                   }
                }
            }
         }
         catch (IllegalArgumentException e)
         {
            log.error("", e);
         }

         return null;
      }

      public void beforeCompletion()
      {
      }
      
      private void notify (User watcher, String from , String subject, String text) {

          Session session = null;

          try {
              session = (Session) PortableRemoteObject
                      .narrow(new InitialContext().lookup("java:Mail"),
                              Session.class);
              try {
                                              
                  StringBuffer buffer = null;
                  Address[] to = null;
                  MimeMessage m = new MimeMessage(session);
                  String email = userProfileModule.getProperty(watcher,User.INFO_USER_EMAIL_REAL).toString(); 
                  if ( email != null ) {
                      m.setFrom(new InternetAddress(from));
                      to = new InternetAddress[] { new InternetAddress(
                              email) };
                      m.setRecipients(RecipientType.TO, to);
                      m.setSubject(subject);

                      m.setSentDate(new Date());
                      buffer = new StringBuffer();

                      buffer.append(text);
                      buffer.append(bundle.getString("EMAIL_FOOTER_MESSAGE"));

                      m.setContent(buffer.toString(),
                              "text/html; charset=\"UTF-8\"");
                      Transport.send(m);
                      
                  }
              } catch (javax.mail.MessagingException e) {
                  log.error(e);
              } catch (IdentityException e2) {
                  log.error(e2);
              }
          } catch (javax.naming.NamingException e) {
              log.error(e);
          }
      }

      public void afterCompletion(int status)
      {
         // When transaction succesfully commits broadcast the notification
         if (status == Status.STATUS_COMMITTED)
         {
            try
            {
               // Do it asynch
               executor.execute(new Runnable()
               {
                  public void run()
                  {
                     try
                     {
                        // Wrap with a tx
                        Transactions.required(tm, NotificationTask.this);
                     }
                     catch (Exception e)
                     {
                        log.error("Cannot broadcast nofication for post id", e);
                     }
                  }
               });
            }
            catch (InterruptedException ignored)
            {
            }
         }
      }
   }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.