[kune-commits] r1658 - in trunk: . src/main/java/cc/kune/core/server src/main/java/cc/kune/core/server/content src/main/java/cc/kune/core/server/mail src/main/java/cc/kune/core/server/manager/impl src/main/java/cc/kune/core/server/notifier src/main/java/cc/kune/core/server/rack src/main/java/cc/kune/core/server/rpc src/main/java/cc/kune/core/server/scheduler src/main/java/cc/kune/gspace/client/options/general src/main/java/cc/kune/lists/server src/main/java/cc/kune/wave/server src/main/java/cc/kune/wave/server/kspecific src/test/java/cc/kune/core/server/notifier

Vicente J. Ruiz Jurado vjrj_ at ourproject.org
Thu Jan 12 02:40:43 CET 2012


Author: vjrj_
Date: 2012-01-12 02:40:41 +0100 (Thu, 12 Jan 2012)
New Revision: 1658

Added:
   trunk/src/main/java/cc/kune/core/server/notifier/DestinationProvider.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotificationHtmlHelper.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotificationSender.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotificationSenderDefault.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotificationService.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotificationType.java
   trunk/src/main/java/cc/kune/core/server/notifier/PendingNotification.java
   trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationDailyJob.java
   trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationHourlyJob.java
   trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationImmediateJob.java
   trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationSender.java
   trunk/src/main/java/cc/kune/core/server/notifier/SimpleDestinationProvider.java
   trunk/src/main/java/cc/kune/core/server/notifier/WaveDestinationProvider.java
   trunk/src/main/java/cc/kune/core/server/scheduler/CustomJobFactory.java
   trunk/src/main/java/cc/kune/wave/server/KuneWaveServerUtils.java
   trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java
   trunk/src/main/java/cc/kune/wave/server/kspecific/pendnotif/
   trunk/src/test/java/cc/kune/core/server/notifier/AbstractPendingNotificationTest.java
   trunk/src/test/java/cc/kune/core/server/notifier/NotificationHtmlHelperTest.java
   trunk/src/test/java/cc/kune/core/server/notifier/PendingNotificationSenderTest.java
   trunk/src/test/java/cc/kune/core/server/notifier/SimpleDestinationProviderTest.java
Removed:
   trunk/src/main/java/cc/kune/core/server/notifier/NotifyHtmlHelper.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotifySender.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotifySenderDefault.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java
   trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java
   trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java
   trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java
   trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java
   trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java
   trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java
   trunk/src/test/java/cc/kune/core/server/notifier/NotifyHtmlHelperTest.java
Modified:
   trunk/DEV-GUIDE
   trunk/TODO
   trunk/src/main/java/cc/kune/core/server/KuneRackModule.java
   trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java
   trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java
   trunk/src/main/java/cc/kune/core/server/mail/FormatedString.java
   trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java
   trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java
   trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java
   trunk/src/main/java/cc/kune/core/server/rpc/SocialNetworkRPC.java
   trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java
   trunk/src/main/java/cc/kune/gspace/client/options/general/UserOptGeneralPresenter.java
   trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java
   trunk/src/main/java/cc/kune/wave/server/kspecific/KuneAgent.java
   trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveService.java
   trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveServiceDefault.java
Log:
NEW - # 185: Implement notification levels (hourly and daily) similar to Google Wave 
http://kune.ourproject.org/issues/ticket/185

Modified: trunk/DEV-GUIDE
===================================================================
--- trunk/DEV-GUIDE	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/DEV-GUIDE	2012-01-12 01:40:41 UTC (rev 1658)
@@ -222,6 +222,8 @@
 
 ====JRuby-Rack====
 
+(This part in now not used, probably we should go back when we return to develop the public part)
+
 We use Rails via [http://kenai.com/projects/jruby-rack/pages/Home JRuby-Rack]. Ruby on Rails + Plugins + Gems are installed in trunk/src/main/webapp/WEB-INF/. Jetty uses these gems when running, but if you run ruby directly with script/server, take into account that you are using your installed local gems.
 
 To install gems inside this directory:
@@ -303,6 +305,14 @@
 
 "Being written in Java, we strongly recommend following the principles outlined in Effective Java. On top of that, patterns that aid testability (dependency injection, etc) are quite important. But beyond that, I don't know if there are any other patterns or practices that would be universal across the whole thing. The web client and the server run in very different environments, so the appropriate patterns change (e.g., the client-only code doesn't have to worry about thread safety, but should worry about excessive short-lived object creation)."
 
+=== Docs about OT, Wave Model, etc ===
+
+http://www.codecommit.com/blog/java/understanding-and-applying-operational-transformation
+Wave Model Deep Dive: http://www.youtube.com/watch?v=6ZqpeFydq4A
+
+Or for a list:
+http://www.youtube.com/user/GoogleDevelopers/search?query=Wave
+
 === Running Hosted Mode without Wave webclient ===
 
 See class WaveClientProvider in Kune (in a short term, we should define this in a .gwt.xml not there, but this is a start point).

Modified: trunk/TODO
===================================================================
--- trunk/TODO	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/TODO	2012-01-12 01:40:41 UTC (rev 1658)
@@ -13,12 +13,15 @@
 
 * SHORT-TERM (URGENT)
 ** Emil notifications for new waves
+*** Migration of DB!!!!!
+*** Text for UI
 Email Notifications
 How often do you want to receive notifications?
     almost immediately
     at most hourly
     at most daily
     I don't need email notifications
+*** Cron and pseudocode
 ** group.inexistentTool nasty error
 ** calendar support
 *** gwt-cal + http://ical4j.sourceforge.net/introduction.html

Modified: trunk/src/main/java/cc/kune/core/server/KuneRackModule.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/KuneRackModule.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/KuneRackModule.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -57,12 +57,15 @@
 import cc.kune.core.server.rest.I18nTranslationJSONService;
 import cc.kune.core.server.rest.TestJSONService;
 import cc.kune.core.server.rest.UserJSONService;
+import cc.kune.core.server.scheduler.CronServerTasksManager;
 import cc.kune.docs.server.DocumentServerModule;
 import cc.kune.events.server.EventsServerModule;
 import cc.kune.hspace.client.ClientStatsService;
 import cc.kune.lists.client.rpc.ListsService;
 import cc.kune.lists.server.ListsServerModule;
 import cc.kune.tasks.server.TaskServerModule;
+import cc.kune.wave.server.KuneWaveServerUtils;
+import cc.kune.wave.server.kspecific.WaveEmailNotifier;
 import cc.kune.wiki.server.WikiServerModule;
 
 import com.google.inject.AbstractModule;
@@ -118,6 +121,7 @@
         if (sessionScope != null) {
           bindScope(SessionScoped.class, sessionScope);
         }
+        requestStaticInjection(KuneWaveServerUtils.class);
       }
     };
   }
@@ -128,7 +132,11 @@
     installGuiceModules(builder);
 
     builder.add(KuneContainerListener.class);
+    builder.add(WaveEmailNotifier.class);
 
+    // Cron tasks
+    builder.add(CronServerTasksManager.class);
+
     builder.exclude("/http-bind.*");
     builder.exclude("/public/.*");
     builder.exclude("/images/.*");

Modified: trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/PlatformServerModule.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -87,8 +87,8 @@
 import cc.kune.core.server.manager.impl.UserManagerDefault;
 import cc.kune.core.server.mapper.DozerMapper;
 import cc.kune.core.server.mapper.Mapper;
-import cc.kune.core.server.notifier.NotifySender;
-import cc.kune.core.server.notifier.NotifySenderDefault;
+import cc.kune.core.server.notifier.NotificationSender;
+import cc.kune.core.server.notifier.NotificationSenderDefault;
 import cc.kune.core.server.notifier.UsersOnline;
 import cc.kune.core.server.rpc.ContentRPC;
 import cc.kune.core.server.rpc.GroupRPC;
@@ -114,7 +114,6 @@
 import cc.kune.wave.server.ParticipantUtils;
 import cc.kune.wave.server.kspecific.KuneWaveService;
 import cc.kune.wave.server.kspecific.KuneWaveServiceDefault;
-import cc.kune.wave.server.kspecific.WaveEmailNotifier;
 
 import com.google.inject.Singleton;
 import com.google.inject.matcher.Matchers;
@@ -197,8 +196,7 @@
     bind(UsersOnline.class).to(UserSessionManager.class).in(Singleton.class);
     requestStaticInjection(AccessRightsUtils.class);
     bind(CronServerTasksManager.class).in(Singleton.class);
-    bind(NotifySender.class).to(NotifySenderDefault.class).in(Singleton.class);
-    bind(WaveEmailNotifier.class).in(Singleton.class);
+    bind(NotificationSender.class).to(NotificationSenderDefault.class).in(Singleton.class);
     bindInterceptor(Matchers.any(), Matchers.annotatedWith(Authenticated.class),
         outermostCall(new AuthenticatedMethodInterceptor()));
     bindInterceptor(Matchers.any(), Matchers.annotatedWith(Authorizated.class),

Modified: trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/content/ContentManagerDefault.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -56,7 +56,7 @@
 import cc.kune.domain.finders.ContentFinder;
 import cc.kune.domain.finders.I18nLanguageFinder;
 import cc.kune.domain.finders.UserFinder;
-import cc.kune.wave.server.KuneWaveUtils;
+import cc.kune.wave.server.KuneWaveServerUtils;
 import cc.kune.wave.server.ParticipantUtils;
 import cc.kune.wave.server.kspecific.KuneWaveService;
 
@@ -104,7 +104,7 @@
   }
 
   public void addGadgetToContent(final User user, final Content content, final URL gadgetUrl) {
-    kuneWaveManager.addGadget(KuneWaveUtils.getWaveRef(content),
+    kuneWaveManager.addGadget(KuneWaveServerUtils.getWaveRef(content),
         participantUtils.of(user.getShortName()).toString(), gadgetUrl);
   }
 
@@ -112,7 +112,7 @@
   public void addParticipant(final User user, final Long contentId, final String participant) {
     final Content content = finder.getContent(contentId);
     if (content.isWave()) {
-      kuneWaveManager.addParticipants(KuneWaveUtils.getWaveRef(content),
+      kuneWaveManager.addParticipants(KuneWaveServerUtils.getWaveRef(content),
           content.getAuthors().get(0).getShortName(), user.getShortName(), participant);
     }
   }
@@ -243,7 +243,7 @@
     content.getLastRevision().setTitle(newTitleWithoutNL);
     if (content.isWave()) {
       final String author = content.getAuthors().get(0).getShortName();
-      kuneWaveManager.setTitle(KuneWaveUtils.getWaveRef(content), newTitle, author);
+      kuneWaveManager.setTitle(KuneWaveServerUtils.getWaveRef(content), newTitle, author);
     }
     setModifiedTime(content);
     return content;

Modified: trunk/src/main/java/cc/kune/core/server/mail/FormatedString.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/mail/FormatedString.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/mail/FormatedString.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,5 +1,8 @@
 package cc.kune.core.server.mail;
 
+import java.util.Arrays;
+
+import com.calclab.emite.core.client.packet.TextUtils;
 import com.google.common.base.Preconditions;
 
 /**
@@ -139,4 +142,11 @@
   public boolean shouldBeTranslated() {
     return shouldBeTranslated;
   }
+
+  @Override
+  public String toString() {
+    return "FormatedString ['" + TextUtils.ellipsis(template, 40) + "', args=" + Arrays.toString(args)
+        + ", shouldBeTranslated=" + shouldBeTranslated + "]";
+  }
+
 }

Modified: trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/manager/impl/KuneWaveManagerDefault.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -36,7 +36,7 @@
 import cc.kune.domain.User;
 import cc.kune.domain.UserBuddiesData;
 import cc.kune.domain.finders.GroupFinder;
-import cc.kune.wave.server.KuneWaveUtils;
+import cc.kune.wave.server.KuneWaveServerUtils;
 import cc.kune.wave.server.ParticipantUtils;
 import cc.kune.wave.server.kspecific.KuneWaveService;
 
@@ -71,7 +71,7 @@
     for (final String part : participants) {
       partIds.add(participantUtils.of(part));
     }
-    return KuneWaveUtils.getUrl(waveService.createWave(title, body,
+    return KuneWaveServerUtils.getUrl(waveService.createWave(title, body,
         partIds.toArray(new ParticipantId[0])));
   }
 
@@ -104,6 +104,6 @@
         toList.addAll(group.getSocialNetwork().getAccessLists().getEditors().getList());
       }
     }
-    return KuneWaveUtils.getUrl(waveService.createWave(title, message, participantUtils.listFrom(toList)));
+    return KuneWaveServerUtils.getUrl(waveService.createWave(title, message, participantUtils.listFrom(toList)));
   }
 }

Modified: trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/manager/impl/UserManagerDefault.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -57,7 +57,7 @@
 import cc.kune.core.server.manager.I18nLanguageManager;
 import cc.kune.core.server.manager.SearchResult;
 import cc.kune.core.server.manager.UserManager;
-import cc.kune.core.server.notifier.NotifyService;
+import cc.kune.core.server.notifier.NotificationService;
 import cc.kune.core.server.properties.ChatProperties;
 import cc.kune.core.server.properties.KuneBasicProperties;
 import cc.kune.core.server.xmpp.ChatConnection;
@@ -89,7 +89,7 @@
   private final I18nTranslationServiceMultiLang i18n;
   private final KuneWaveService kuneWaveManager;
   private final I18nLanguageManager languageManager;
-  private final NotifyService notifyService;
+  private final NotificationService notifyService;
   private final ParticipantUtils participantUtils;
   private final KuneBasicProperties properties;
   private final UserFinder userFinder;
@@ -104,7 +104,7 @@
       final I18nTranslationServiceMultiLang i18n, final CustomUserRegistrationServlet waveUserRegister,
       final AccountStore waveAccountStore, final KuneWaveService kuneWaveManager,
       final ParticipantUtils participantUtils, final KuneBasicProperties properties,
-      final GroupManager groupManager, final NotifyService notifyService) {
+      final GroupManager groupManager, final NotificationService notifyService) {
     super(provider, User.class);
     this.userFinder = finder;
     this.languageManager = languageManager;

Added: trunk/src/main/java/cc/kune/core/server/notifier/DestinationProvider.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/DestinationProvider.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/DestinationProvider.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,19 @@
+package cc.kune.core.server.notifier;
+
+import java.util.Collection;
+
+import cc.kune.domain.User;
+
+/**
+ * The Interface DestinationProvider is used to provide a way to get a list of
+ * Users (for instance to send notifications to them)
+ */
+public interface DestinationProvider {
+
+  /**
+   * Gets the destination list
+   * 
+   * @return the destination
+   */
+  Collection<User> getDest();
+}

Copied: trunk/src/main/java/cc/kune/core/server/notifier/NotificationHtmlHelper.java (from rev 1655, trunk/src/main/java/cc/kune/core/server/notifier/NotifyHtmlHelper.java)
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotificationHtmlHelper.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotificationHtmlHelper.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,59 @@
+package cc.kune.core.server.notifier;
+
+import cc.kune.core.server.mail.FormatedString;
+import cc.kune.core.server.utils.AbsoluteFileDownloadUtils;
+import cc.kune.core.shared.utils.SharedFileDownloadUtils;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The Class NotifyHtmlHelper is used to get html snippets for email
+ * notifications.
+ */
+ at Singleton
+public class NotificationHtmlHelper {
+
+  /** The template used from messages snippets from a group */
+  private static String GROUP_TEMPLATE = "<table style=\"FIXME\" border=\"0\" cellpadding=\"2\" cellspacing=\"2\" width=\"100%%\">"
+      + "<tbody><tr>"
+      + "<td style=\"\" valign=\"top\"><a href=\"%s\">%s</a></td>"
+      + "<td style=\"\" valign=\"top\" width=\"100%%\">"
+      + "<a href=\"%s\">%s</a><br>"
+      + "%s"
+      + "</td></tr></tbody></table>";
+
+  private final SharedFileDownloadUtils fileDownloadUtils;
+
+  /**
+   * Instantiates a new notify html helper.
+   * 
+   * @param fileDownloadUtils
+   *          the file download utils
+   */
+  @Inject
+  public NotificationHtmlHelper(final AbsoluteFileDownloadUtils fileDownloadUtils) {
+    this.fileDownloadUtils = fileDownloadUtils;
+  }
+
+  /**
+   * Generates a group notification in html like [logo|message]
+   * 
+   * @param groupName
+   *          the group name you want to get the notification
+   * @param hasLogo
+   *          the has logo?
+   * @param message
+   *          the message to show close to the logo
+   * @param readMoreMsg
+   *          the read more msg
+   * @return the html string
+   */
+  public FormatedString groupNotification(final String groupName, final boolean hasLogo,
+      final String message) {
+    final String groupUrl = fileDownloadUtils.getPrefix() + "#" + groupName;
+    return FormatedString.build(false, GROUP_TEMPLATE, groupUrl,
+        fileDownloadUtils.getLogoAvatarHtml(groupName, hasLogo, false, 50, 50), groupUrl, groupName,
+        message);
+  }
+}

Added: trunk/src/main/java/cc/kune/core/server/notifier/NotificationSender.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotificationSender.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotificationSender.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,20 @@
+package cc.kune.core.server.notifier;
+
+import cc.kune.core.shared.domain.dto.EmailNotificationFrequency;
+
+/**
+ * The Interface PendingNotificationSender. Used to send pending notifications
+ */
+public interface NotificationSender {
+
+  /**
+   * Send the notification to users with some frequency configured
+   * 
+   * @param notification
+   *          the notification to send
+   * @param currentFrequency
+   *          the current frequency (only users with this frequency should be
+   *          processed
+   */
+  void send(PendingNotification notification, EmailNotificationFrequency currentFrequency);
+}

Copied: trunk/src/main/java/cc/kune/core/server/notifier/NotificationSenderDefault.java (from rev 1657, trunk/src/main/java/cc/kune/core/server/notifier/NotifySenderDefault.java)
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotificationSenderDefault.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotificationSenderDefault.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,105 @@
+package cc.kune.core.server.notifier;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import cc.kune.common.shared.utils.TextUtils;
+import cc.kune.core.server.i18n.I18nTranslationServiceMultiLang;
+import cc.kune.core.server.mail.FormatedString;
+import cc.kune.core.server.mail.MailService;
+import cc.kune.core.server.properties.KuneProperties;
+import cc.kune.core.server.xmpp.XmppManager;
+import cc.kune.core.shared.domain.dto.EmailNotificationFrequency;
+import cc.kune.domain.User;
+import cc.kune.wave.server.kspecific.KuneWaveService;
+
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+ at Singleton
+public class NotificationSenderDefault implements NotificationSender {
+  public static final Log LOG = LogFactory.getLog(NotificationSenderDefault.class);
+  private final String emailTemplate;
+  private final I18nTranslationServiceMultiLang i18n;
+  private final MailService mailService;
+  private final String subjectPrefix;
+  private final UsersOnline usersOnline;
+  private final KuneWaveService waveService;
+  private final XmppManager xmppManager;
+
+  @Inject
+  public NotificationSenderDefault(final MailService mailService, final KuneWaveService waveService,
+      final XmppManager xmppManager, final I18nTranslationServiceMultiLang i18n,
+      final UsersOnline usersOnline, final KuneProperties kuneProperties) throws IOException {
+    this.mailService = mailService;
+    this.waveService = waveService;
+    this.xmppManager = xmppManager;
+    this.i18n = i18n;
+    this.usersOnline = usersOnline;
+    emailTemplate = FileUtils.readFileToString(new File(
+        kuneProperties.get(KuneProperties.SITE_EMAIL_TEMPLATE)));
+    Preconditions.checkNotNull(emailTemplate);
+    Preconditions.checkArgument(TextUtils.notEmpty(emailTemplate));
+    subjectPrefix = new StringBuffer("[").append(kuneProperties.get(KuneProperties.SITE_NAME)).append(
+        "] ").toString();
+  }
+
+  @Override
+  public void send(final PendingNotification notification, final EmailNotificationFrequency withFrequency) {
+    for (final User user : notification.getDestProvider().getDest()) {
+      final String username = user.getShortName();
+      final FormatedString subject = notification.getSubject();
+      final FormatedString body = notification.getBody();
+      final NotificationType notifyType = notification.getNotifyType();
+      final boolean forceSend = notification.isForceSend();
+      final boolean isHtml = notification.isHtml();
+
+      subject.setTemplate(subjectPrefix + subject.getTemplate());
+      if (subject.shouldBeTranslated()) {
+        // Translate per recipient language
+        // final String subjectTranslation = i18n.tWithNT(user.getLanguage(),
+        // subject.getTemplate(), "");
+        // if (subjectTranslation != null) {
+        // Right now commented because we are only testing
+        // subject.setTemplate(subjectTranslation);
+        // }
+      }
+      if (body.shouldBeTranslated()) {
+        // final String bodyTranslation = i18n.tWithNT(user.getLanguage(),
+        // body.getTemplate(), "");
+        // if (bodyTranslation != null) {
+        // Right now commented because we are only testing
+        // body.setTemplate(bodyTranslation);
+        // }
+      }
+      switch (notifyType) {
+      case chat:
+        // FIXME seems that html is not sending correctly... check server specs
+        xmppManager.sendMessage(username,
+            String.format("<b>%s</b>%s", subject.getString(), body.getString()));
+        break;
+      case email:
+        if (forceSend || (!usersOnline.isLogged(username) && withFrequency == user.getEmailNotifFreq())) {
+          // we'll send this notification if is mandatory or this user is not
+          // only and has this freq configured
+          mailService.send(subject, FormatedString.build(emailTemplate.replace("%s", body.getString())),
+              isHtml, user.getEmail());
+        }
+        break;
+      case wave:
+        if (isHtml) {
+          LOG.error("Wave html messages not supported yet");
+        }
+        waveService.createWave(subject.getString(), body.getString(), username);
+        break;
+      }
+    }
+
+  }
+
+}

Copied: trunk/src/main/java/cc/kune/core/server/notifier/NotificationService.java (from rev 1657, trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java)
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotificationService.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotificationService.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,92 @@
+package cc.kune.core.server.notifier;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.NoResultException;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import cc.kune.core.server.mail.FormatedString;
+import cc.kune.domain.Group;
+import cc.kune.domain.User;
+import cc.kune.domain.finders.UserFinder;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+ at Singleton
+public class NotificationService {
+
+  public static final Log LOG = LogFactory.getLog(NotificationService.class);
+  private final NotificationHtmlHelper helper;
+  private final PendingNotificationSender sender;
+  private final UserFinder userFinder;
+
+  @Inject
+  NotificationService(final PendingNotificationSender sender, final NotificationHtmlHelper helper,
+      final UserFinder userFinder) {
+    this.sender = sender;
+    this.helper = helper;
+    this.userFinder = userFinder;
+  }
+
+  @SuppressWarnings("unchecked")
+  private void getAllUserMembers(final Set<User> users, final Group groupToNotify,
+      final boolean onlyAdmins) {
+    final Collection<Group> members;
+    final Set<Group> admins = groupToNotify.getSocialNetwork().getAccessLists().getAdmins().getList();
+    if (onlyAdmins) {
+      members = admins;
+    } else {
+      final Set<Group> collabs = groupToNotify.getSocialNetwork().getAccessLists().getEditors().getList();
+      members = CollectionUtils.union(admins, collabs);
+    }
+    for (final Group member : members) {
+      if (member.isPersonal()) {
+        final String shortName = member.getShortName();
+        try {
+          final User user = userFinder.findByShortName(shortName);
+          users.add(user);
+        } catch (final NoResultException e) {
+          LOG.error(String.format("This personal group %s is not a local user", shortName));
+        }
+      } else {
+        // Is a group, so go recursively
+        getAllUserMembers(users, member, onlyAdmins);
+      }
+    }
+
+  }
+
+  public void notifyGroup(final Group groupToNotify, final Group groupSender, final String subject,
+      final String message) {
+    final Set<User> members = new HashSet<User>();
+    getAllUserMembers(members, groupToNotify, false);
+    notifyToAll(groupSender, subject, message, members);
+  }
+
+  public void notifyGroupAdmins(final Group groupToNotify, final Group groupSender,
+      final String subject, final String message) {
+    final Set<User> adminMembers = new HashSet<User>();
+    getAllUserMembers(adminMembers, groupToNotify, true);
+    notifyToAll(groupSender, subject, message, adminMembers);
+  }
+
+  private void notifyToAll(final Group groupSender, final String subject, final String message,
+      final Collection<User> users) {
+    for (final User to : users) {
+      sender.add(NotificationType.email, FormatedString.build(subject),
+          helper.groupNotification(groupSender.getShortName(), groupSender.hasLogo(), message), true,
+          true, to);
+    }
+  }
+
+  public void notifyUser(final User to, final Group group, final String subject, final String message) {
+    sender.add(NotificationType.email, FormatedString.build(subject),
+        helper.groupNotification(group.getShortName(), group.hasLogo(), message), true, true, to);
+  }
+}

Copied: trunk/src/main/java/cc/kune/core/server/notifier/NotificationType.java (from rev 1655, trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java)
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotificationType.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotificationType.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,9 @@
+package cc.kune.core.server.notifier;
+
+/**
+ * Type of notifications for users
+ * 
+ */
+public enum NotificationType {
+  chat, email, wave
+}

Deleted: trunk/src/main/java/cc/kune/core/server/notifier/NotifyHtmlHelper.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotifyHtmlHelper.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotifyHtmlHelper.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,59 +0,0 @@
-package cc.kune.core.server.notifier;
-
-import cc.kune.core.server.mail.FormatedString;
-import cc.kune.core.server.utils.AbsoluteFileDownloadUtils;
-import cc.kune.core.shared.utils.SharedFileDownloadUtils;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-/**
- * The Class NotifyHtmlHelper is used to get html snippets for email
- * notifications.
- */
- at Singleton
-public class NotifyHtmlHelper {
-
-  /** The template used from messages snippets from a group */
-  private static String GROUP_TEMPLATE = "<table style=\"FIXME\" border=\"0\" cellpadding=\"2\" cellspacing=\"2\" width=\"100%%\">"
-      + "<tbody><tr>"
-      + "<td style=\"\" valign=\"top\"><a href=\"%s\">%s</a></td>"
-      + "<td style=\"\" valign=\"top\" width=\"100%%\">"
-      + "<a href=\"%s\">%s</a><br>"
-      + "%s"
-      + "</td></tr></tbody></table>";
-
-  private final SharedFileDownloadUtils fileDownloadUtils;
-
-  /**
-   * Instantiates a new notify html helper.
-   * 
-   * @param fileDownloadUtils
-   *          the file download utils
-   */
-  @Inject
-  public NotifyHtmlHelper(final AbsoluteFileDownloadUtils fileDownloadUtils) {
-    this.fileDownloadUtils = fileDownloadUtils;
-  }
-
-  /**
-   * Generates a group notification in html like [logo|message]
-   * 
-   * @param groupName
-   *          the group name you want to get the notification
-   * @param hasLogo
-   *          the has logo?
-   * @param message
-   *          the message to show close to the logo
-   * @param readMoreMsg
-   *          the read more msg
-   * @return the html string
-   */
-  public FormatedString groupNotification(final String groupName, final boolean hasLogo,
-      final String message) {
-    final String groupUrl = fileDownloadUtils.getPrefix() + "#" + groupName;
-    return FormatedString.build(false, GROUP_TEMPLATE, groupUrl,
-        fileDownloadUtils.getLogoAvatarHtml(groupName, hasLogo, false, 50, 50), groupUrl, groupName,
-        message);
-  }
-}

Deleted: trunk/src/main/java/cc/kune/core/server/notifier/NotifySender.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotifySender.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotifySender.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,49 +0,0 @@
-package cc.kune.core.server.notifier;
-
-import cc.kune.core.server.mail.FormatedString;
-import cc.kune.domain.User;
-
-/**
- * The Interface NotifySender.
- */
-public interface NotifySender {
-
-  /**
-   * Send a html message to the recipients (also translate the subject/body
-   * using the user language)
-   * 
-   * @param notifyType
-   *          the notify type (email, etc)
-   * @param subject
-   *          the subject of the message (not translated)
-   * @param body
-   *          the body of the message (not translated) but with %s
-   *          {@link String.format} args
-   * @param isHtml
-   *          if the body is html
-   * @param forceSend
-   *          send even this user has "no notifications" selected
-   * @param recipients
-   *          the recipients
-   */
-  void send(NotifyType notifyType, FormatedString subject, FormatedString body, boolean isHtml,
-      final boolean forceSend, User... recipients);
-
-  /**
-   * Send a text message to the recipients (also translate the subject/body
-   * using the user language)
-   * 
-   * @param notifyType
-   *          the notify type (email, etc)
-   * @param subject
-   *          the subject of the message
-   * @param body
-   *          the body of the message (no translated) but with some %s
-   *          {@link String.format} args
-   * @param recipients
-   *          the recipients
-   */
-  @Deprecated
-  void send(NotifyType notifyType, FormatedString subject, FormatedString body, User... recipients);
-
-}

Deleted: trunk/src/main/java/cc/kune/core/server/notifier/NotifySenderDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotifySenderDefault.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotifySenderDefault.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,109 +0,0 @@
-package cc.kune.core.server.notifier;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import cc.kune.common.shared.utils.TextUtils;
-import cc.kune.core.server.i18n.I18nTranslationServiceMultiLang;
-import cc.kune.core.server.mail.FormatedString;
-import cc.kune.core.server.mail.MailService;
-import cc.kune.core.server.properties.KuneProperties;
-import cc.kune.core.server.xmpp.XmppManager;
-import cc.kune.core.shared.domain.dto.EmailNotificationFrequency;
-import cc.kune.domain.User;
-import cc.kune.wave.server.kspecific.KuneWaveService;
-
-import com.google.common.base.Preconditions;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
- at Singleton
-public class NotifySenderDefault implements NotifySender {
-  public static final Log LOG = LogFactory.getLog(NotifySenderDefault.class);
-  private final String emailTemplate;
-  private final I18nTranslationServiceMultiLang i18n;
-  private final MailService mailService;
-  private final String subjectPrefix;
-  private final UsersOnline usersOnline;
-  private final KuneWaveService waveService;
-  private final XmppManager xmppManager;
-
-  @Inject
-  public NotifySenderDefault(final MailService mailService, final KuneWaveService waveService,
-      final XmppManager xmppManager, final I18nTranslationServiceMultiLang i18n,
-      final UsersOnline usersOnline, final KuneProperties kuneProperties) throws IOException {
-    this.mailService = mailService;
-    this.waveService = waveService;
-    this.xmppManager = xmppManager;
-    this.i18n = i18n;
-    this.usersOnline = usersOnline;
-    emailTemplate = FileUtils.readFileToString(new File(
-        kuneProperties.get(KuneProperties.SITE_EMAIL_TEMPLATE)));
-    Preconditions.checkNotNull(emailTemplate);
-    Preconditions.checkArgument(TextUtils.notEmpty(emailTemplate));
-    subjectPrefix = new StringBuffer("[").append(kuneProperties.get(KuneProperties.SITE_NAME)).append(
-        "] ").toString();
-  }
-
-  @Override
-  public void send(final NotifyType notifyType, final FormatedString subject, final FormatedString body,
-      final boolean isHtml, final boolean forceSend, final User... recipients) {
-    for (final User user : recipients) {
-      final String username = user.getShortName();
-      subject.setTemplate(subjectPrefix + subject.getTemplate());
-      if (subject.shouldBeTranslated()) {
-        // Translate per recipient language
-        // final String subjectTranslation = i18n.tWithNT(user.getLanguage(),
-        // subject.getTemplate(), "");
-        // if (subjectTranslation != null) {
-        // Right now commented because we are only testing
-        // subject.setTemplate(subjectTranslation);
-        // }
-      }
-      if (body.shouldBeTranslated()) {
-        // final String bodyTranslation = i18n.tWithNT(user.getLanguage(),
-        // body.getTemplate(), "");
-        // if (bodyTranslation != null) {
-        // Right now commented because we are only testing
-        // body.setTemplate(bodyTranslation);
-        // }
-      }
-      switch (notifyType) {
-      case chat:
-        // FIXME seems that html is not sending correctly... check server specs
-        xmppManager.sendMessage(username,
-            String.format("<b>%s</b>%s", subject.getString(), body.getString()));
-        break;
-      case email:
-        if (forceSend || !usersOnline.isLogged(username)) {
-          if (user.getEmailNotifFreq().equals(EmailNotificationFrequency.immediately)) {
-            mailService.send(subject,
-                FormatedString.build(emailTemplate.replace("%s", body.getString())), isHtml,
-                user.getEmail());
-          } else {
-            // TODO: handle other types of notifications frequencies
-          }
-        }
-        break;
-      case wave:
-        if (isHtml) {
-          LOG.error("Wave html messages not supported yet");
-        }
-        waveService.createWave(subject.getString(), body.getString(), username);
-        break;
-      }
-    }
-  }
-
-  @Override
-  @Deprecated
-  public void send(final NotifyType notifyType, final FormatedString subject, final FormatedString body,
-      final User... dests) {
-    send(notifyType, subject, body, false, false, dests);
-  }
-
-}

Deleted: trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotifyService.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,91 +0,0 @@
-package cc.kune.core.server.notifier;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import javax.persistence.NoResultException;
-
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import cc.kune.core.server.mail.FormatedString;
-import cc.kune.domain.Group;
-import cc.kune.domain.User;
-import cc.kune.domain.finders.UserFinder;
-
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
- at Singleton
-public class NotifyService {
-
-  public static final Log LOG = LogFactory.getLog(NotifyService.class);
-  private final NotifyHtmlHelper helper;
-  private final NotifySender sender;
-  private final UserFinder userFinder;
-
-  @Inject
-  NotifyService(final NotifySender sender, final NotifyHtmlHelper helper, final UserFinder userFinder) {
-    this.sender = sender;
-    this.helper = helper;
-    this.userFinder = userFinder;
-  }
-
-  @SuppressWarnings("unchecked")
-  private void getAllUserMembers(final Set<User> users, final Group groupToNotify,
-      final boolean onlyAdmins) {
-    final Collection<Group> members;
-    final Set<Group> admins = groupToNotify.getSocialNetwork().getAccessLists().getAdmins().getList();
-    if (onlyAdmins) {
-      members = admins;
-    } else {
-      final Set<Group> collabs = groupToNotify.getSocialNetwork().getAccessLists().getEditors().getList();
-      members = CollectionUtils.union(admins, collabs);
-    }
-    for (final Group member : members) {
-      if (member.isPersonal()) {
-        final String shortName = member.getShortName();
-        try {
-          final User user = userFinder.findByShortName(shortName);
-          users.add(user);
-        } catch (final NoResultException e) {
-          LOG.error(String.format("This personal group %s is not a local user", shortName));
-        }
-      } else {
-        // Is a group, so go recursively
-        getAllUserMembers(users, member, onlyAdmins);
-      }
-    }
-
-  }
-
-  public void notifyGroup(final Group groupToNotify, final Group groupSender, final String subject,
-      final String message) {
-    final Set<User> members = new HashSet<User>();
-    getAllUserMembers(members, groupToNotify, false);
-    notifyToAll(groupSender, subject, message, members);
-  }
-
-  public void notifyGroupAdmins(final Group groupToNotify, final Group groupSender,
-      final String subject, final String message) {
-    final Set<User> adminMembers = new HashSet<User>();
-    getAllUserMembers(adminMembers, groupToNotify, true);
-    notifyToAll(groupSender, subject, message, adminMembers);
-  }
-
-  private void notifyToAll(final Group groupSender, final String subject, final String message,
-      final Collection<User> users) {
-    for (final User to : users) {
-      sender.send(NotifyType.email, FormatedString.build(subject),
-          helper.groupNotification(groupSender.getShortName(), groupSender.hasLogo(), message), true,
-          true, to);
-    }
-  }
-
-  public void notifyUser(final User to, final Group group, final String subject, final String message) {
-    sender.send(NotifyType.email, FormatedString.build(subject),
-        helper.groupNotification(group.getShortName(), group.hasLogo(), message), true, true, to);
-  }
-}

Deleted: trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/notifier/NotifyType.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,9 +0,0 @@
-package cc.kune.core.server.notifier;
-
-/**
- * Type of notifications for users
- * 
- */
-public enum NotifyType {
-  chat, email, wave
-}

Added: trunk/src/main/java/cc/kune/core/server/notifier/PendingNotification.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/PendingNotification.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/PendingNotification.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,110 @@
+package cc.kune.core.server.notifier;
+
+import cc.kune.core.server.mail.FormatedString;
+
+/**
+ * The Class PendingNotification is used to store and send notifications (for
+ * instance email) via cron
+ */
+public class PendingNotification {
+
+  /** The body. */
+  private final FormatedString body;
+
+  /** The dest provider. */
+  private final DestinationProvider destProvider;
+
+  /** The force send. */
+  private final boolean forceSend;
+
+  /** The is html. */
+  private final boolean isHtml;
+
+  /** The notify type. */
+  private final NotificationType notifyType;
+
+  /** The subject. */
+  private final FormatedString subject;
+
+  /**
+   * Instantiates a new pending notification
+   * 
+   * @param notifyType
+   *          the notify type
+   * @param subject
+   *          the subject
+   * @param body
+   *          the body
+   * @param isHtml
+   *          the is html
+   * @param forceSend
+   *          the force send
+   * @param destProvider
+   *          the dest provider
+   */
+  public PendingNotification(final NotificationType notifyType, final FormatedString subject,
+      final FormatedString body, final boolean isHtml, final boolean forceSend,
+      final DestinationProvider destProvider) {
+    this.notifyType = notifyType;
+    this.subject = subject;
+    this.body = body;
+    this.isHtml = isHtml;
+    this.forceSend = forceSend;
+    this.destProvider = destProvider;
+  }
+
+  /**
+   * Gets the body.
+   * 
+   * @return the body
+   */
+  public FormatedString getBody() {
+    return body;
+  }
+
+  /**
+   * Gets the dest provider.
+   * 
+   * @return the dest provider
+   */
+  public DestinationProvider getDestProvider() {
+    return destProvider;
+  }
+
+  /**
+   * Gets the notify type.
+   * 
+   * @return the notify type
+   */
+  public NotificationType getNotifyType() {
+    return notifyType;
+  }
+
+  /**
+   * Gets the subject.
+   * 
+   * @return the subject
+   */
+  public FormatedString getSubject() {
+    return subject;
+  }
+
+  /**
+   * Checks if is force send.
+   * 
+   * @return true, if is force send
+   */
+  public boolean isForceSend() {
+    return forceSend;
+  }
+
+  /**
+   * Checks if is html.
+   * 
+   * @return true, if is html
+   */
+  public boolean isHtml() {
+    return isHtml;
+  }
+
+}

Added: trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationDailyJob.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationDailyJob.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationDailyJob.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,33 @@
+package cc.kune.core.server.notifier;
+
+import java.text.ParseException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.quartz.SchedulerException;
+
+import com.google.inject.Inject;
+
+public class PendingNotificationDailyJob implements Job {
+
+  public static final Log LOG = LogFactory.getLog(PendingNotificationDailyJob.class);
+
+  private final PendingNotificationSender pendingManager;
+
+  @Inject
+  public PendingNotificationDailyJob(final PendingNotificationSender pendingManager)
+      throws ParseException, SchedulerException {
+    this.pendingManager = pendingManager;
+  }
+
+  @Override
+  public void execute(final JobExecutionContext context) throws JobExecutionException {
+    LOG.info(String.format("Daily notifications cron job start, %s", pendingManager));
+    pendingManager.sendDailyNotifications();
+    LOG.info(String.format("Daily notifications cron job end, %s", pendingManager));
+  }
+
+}

Added: trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationHourlyJob.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationHourlyJob.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationHourlyJob.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,38 @@
+package cc.kune.core.server.notifier;
+
+import java.text.ParseException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.quartz.SchedulerException;
+
+import cc.kune.wave.server.kspecific.WaveEmailNotifier;
+
+import com.google.inject.Inject;
+
+public class PendingNotificationHourlyJob implements Job {
+
+  public static final Log LOG = LogFactory.getLog(PendingNotificationHourlyJob.class);
+  private final PendingNotificationSender pendingManager;
+
+  private final WaveEmailNotifier waveNotifier;
+
+  @Inject
+  public PendingNotificationHourlyJob(final PendingNotificationSender pendingManager,
+      final WaveEmailNotifier waveNotifier) throws ParseException, SchedulerException {
+    this.pendingManager = pendingManager;
+    this.waveNotifier = waveNotifier;
+  }
+
+  @Override
+  public void execute(final JobExecutionContext context) throws JobExecutionException {
+    LOG.info(String.format("Hourly notifications cron job start, %s", pendingManager));
+    pendingManager.sendHourlyNotifications();
+    waveNotifier.clearUpdatedWaves();
+    LOG.info(String.format("Hourly notifications cron job end, %s", pendingManager));
+  }
+
+}

Added: trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationImmediateJob.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationImmediateJob.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationImmediateJob.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,33 @@
+package cc.kune.core.server.notifier;
+
+import java.text.ParseException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.quartz.SchedulerException;
+
+import com.google.inject.Inject;
+
+public class PendingNotificationImmediateJob implements Job {
+
+  public static final Log LOG = LogFactory.getLog(PendingNotificationImmediateJob.class);
+
+  private final PendingNotificationSender pendingManager;
+
+  @Inject
+  public PendingNotificationImmediateJob(final PendingNotificationSender pendingManager)
+      throws ParseException, SchedulerException {
+    this.pendingManager = pendingManager;
+  }
+
+  @Override
+  public void execute(final JobExecutionContext context) throws JobExecutionException {
+    LOG.info(String.format("Immediate notifications cron job start, %s", pendingManager));
+    pendingManager.sendImmediateNotifications();
+    LOG.info(String.format("Immediate notifications cron job end, %s", pendingManager));
+  }
+
+}

Added: trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationSender.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationSender.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/PendingNotificationSender.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,148 @@
+package cc.kune.core.server.notifier;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import cc.kune.core.server.mail.FormatedString;
+import cc.kune.core.shared.domain.dto.EmailNotificationFrequency;
+import cc.kune.domain.User;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The Class PendingNotificationSender is used to store and send pending
+ * notifications via cron tasks.
+ */
+ at Singleton
+public class PendingNotificationSender {
+
+  /** The Constant NO_NEXT. */
+  private static final Collection<PendingNotification> NO_NEXT = null;
+
+  /** The daily pend notif. list */
+  private final Set<PendingNotification> dailyPendNotif;
+
+  /** The houry pend notif. list */
+  private final Set<PendingNotification> hourlyPendNotif;
+
+  /** The immediate pend notif. list */
+  private final Set<PendingNotification> immediatePendNotif;
+
+  /** The sender. */
+  private final NotificationSender sender;
+
+  /**
+   * Instantiates a new pending notifications manager.
+   * 
+   * @param sender
+   *          the sender
+   */
+  @Inject
+  public PendingNotificationSender(final NotificationSender sender) {
+    this.sender = sender;
+    immediatePendNotif = new HashSet<PendingNotification>();
+    hourlyPendNotif = new HashSet<PendingNotification>();
+    dailyPendNotif = new HashSet<PendingNotification>();
+  }
+
+  public void add(final NotificationType type, final FormatedString subject, final FormatedString body,
+      final boolean isHtml, final boolean forceSend, final User to) {
+    add(new PendingNotification(type, subject, body, isHtml, forceSend,
+        new SimpleDestinationProvider(to)));
+  }
+
+  /**
+   * Adds a pending notification.
+   * 
+   * @param notification
+   *          the notification
+   */
+  public void add(final PendingNotification notification) {
+    if (!hourlyPendNotif.contains(notification)) {
+      // If we have send a similar notification this hour just ignore
+      immediatePendNotif.add(notification);
+    }
+  }
+
+  /**
+   * Gets the daily pending notifications count.
+   * 
+   * @return the daily count
+   */
+  public int getDailyCount() {
+    return dailyPendNotif.size();
+  }
+
+  /**
+   * Gets the hourly pending notifications count.
+   * 
+   * @return the hourly count
+   */
+  public int getHourlyCount() {
+    return hourlyPendNotif.size();
+  }
+
+  /**
+   * Gets the immediate pending notifications count.
+   * 
+   * @return the immediate count
+   */
+  public int getImmediateCount() {
+    return immediatePendNotif.size();
+  }
+
+  /**
+   * Send some list of notifications (called vía cron).
+   * 
+   * @param list
+   *          the list to process
+   * @param nextList
+   *          the next list to store (we have a list of Users some that wants an
+   *          immediate notification and other that want periodical
+   *          notifications instead.
+   * @param currentFreq
+   *          The current frequency of notifications, that is, we'll send
+   *          notifications only to users with this frequency configured
+   */
+  private void send(final Collection<PendingNotification> list,
+      final Collection<PendingNotification> nextList, final EmailNotificationFrequency currentFreq) {
+    for (final PendingNotification notification : list) {
+      sender.send(notification, currentFreq);
+      if (!notification.isForceSend() && nextList != NO_NEXT) {
+        // Forced Send, are send immediately (independent of how User has its
+        // notification configured)!
+        nextList.add(notification);
+      }
+    }
+    list.clear();
+  }
+
+  /**
+   * Send daily notifications.
+   */
+  public void sendDailyNotifications() {
+    send(dailyPendNotif, NO_NEXT, EmailNotificationFrequency.immediately);
+  }
+
+  /**
+   * Send hourly notifications.
+   */
+  public void sendHourlyNotifications() {
+    send(hourlyPendNotif, dailyPendNotif, EmailNotificationFrequency.hourly);
+  }
+
+  /**
+   * Send immediate notifications.
+   */
+  public void sendImmediateNotifications() {
+    send(immediatePendNotif, hourlyPendNotif, EmailNotificationFrequency.daily);
+  }
+
+  @Override
+  public String toString() {
+    return "pendingNotifications: [" + getImmediateCount() + ", " + getHourlyCount() + ", "
+        + getDailyCount() + "]";
+  }
+}

Added: trunk/src/main/java/cc/kune/core/server/notifier/SimpleDestinationProvider.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/SimpleDestinationProvider.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/SimpleDestinationProvider.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,58 @@
+package cc.kune.core.server.notifier;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import cc.kune.domain.User;
+
+public class SimpleDestinationProvider implements DestinationProvider {
+  private final List<User> list;
+
+  /**
+   * Instantiates a new simple destination provider (used for single
+   * notifications like add/remove participant emails).
+   * 
+   * @param user
+   *          the user to send the email or other type of notification
+   */
+  public SimpleDestinationProvider(final User user) {
+    list = Arrays.asList(user);
+  }
+
+  @Override
+  public boolean equals(final Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null) {
+      return false;
+    }
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    final SimpleDestinationProvider other = (SimpleDestinationProvider) obj;
+    if (list == null) {
+      if (other.list != null) {
+        return false;
+      }
+    } else if (!list.equals(other.list)) {
+      return false;
+    }
+    return true;
+  }
+
+  @Override
+  public Collection<User> getDest() {
+    return list;
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((list == null) ? 0 : list.hashCode());
+    return result;
+  }
+
+}

Added: trunk/src/main/java/cc/kune/core/server/notifier/WaveDestinationProvider.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/notifier/WaveDestinationProvider.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/notifier/WaveDestinationProvider.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,88 @@
+package cc.kune.core.server.notifier;
+
+import java.util.Collection;
+
+import org.waveprotocol.wave.model.waveref.WaveRef;
+
+import cc.kune.domain.User;
+import cc.kune.wave.server.KuneWaveServerUtils;
+
+/**
+ * The Class WaveDestinationProvider. A WaveRef is used to get the participants
+ * and to send notifications to them
+ */
+public class WaveDestinationProvider implements DestinationProvider {
+
+  private final String author;
+
+  /** The list. */
+  private Collection<User> list;
+
+  /** The ref. */
+  private final WaveRef ref;
+
+  /**
+   * Instantiates a new wave destination provider.
+   * 
+   * @param ref
+   *          the ref
+   */
+  public WaveDestinationProvider(final WaveRef ref, final String author) {
+    this.ref = ref;
+    this.author = author;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see java.lang.Object#equals(java.lang.Object)
+   */
+  @Override
+  public boolean equals(final Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    if (obj == null) {
+      return false;
+    }
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    final WaveDestinationProvider other = (WaveDestinationProvider) obj;
+    if (ref == null) {
+      if (other.ref != null) {
+        return false;
+      }
+    } else if (!ref.equals(other.ref)) {
+      return false;
+    }
+    return true;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see cc.kune.wave.server.kspecific.pendnotif.DestinationProvider#getDest()
+   */
+  @Override
+  public Collection<User> getDest() {
+    if (list == null) {
+      list = KuneWaveServerUtils.getLocalParticipants(ref, author);
+    }
+    return list;
+  }
+
+  /*
+   * (non-Javadoc)
+   * 
+   * @see java.lang.Object#hashCode()
+   */
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((ref == null) ? 0 : ref.hashCode());
+    return result;
+  }
+
+}

Modified: trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/rack/RackServletFilter.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -32,15 +32,13 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.quartz.SchedulerException;
 import org.waveprotocol.box.server.rpc.ServerRpcProvider;
 
 import cc.kune.core.server.error.ServerException;
 import cc.kune.core.server.rack.dock.Dock;
 import cc.kune.core.server.rack.dock.RequestMatcher;
 import cc.kune.core.server.rack.utils.RackHelper;
-import cc.kune.core.server.scheduler.CronServerTasksManager;
-import cc.kune.wave.server.kspecific.WaveEmailNotifier;
+import cc.kune.core.server.scheduler.CustomJobFactory;
 
 import com.google.inject.Injector;
 
@@ -143,16 +141,12 @@
     rack = builder.getRack();
     injector = (Injector) filterConfig.getServletContext().getAttribute(INJECTOR_PARENT_ATTRIBUTE);
     final Injector kuneChildInjector = installInjector(filterConfig, rack, injector);
+    final CustomJobFactory jobFactory = kuneChildInjector.getInstance(CustomJobFactory.class);
+    jobFactory.setInjector(kuneChildInjector);
     startContainerListeners(rack.getListeners(), kuneChildInjector);
     docks = rack.getDocks();
     excludes = rack.getExcludes();
     initFilters(filterConfig);
-    kuneChildInjector.getInstance(WaveEmailNotifier.class);
-    try {
-      kuneChildInjector.getInstance(CronServerTasksManager.class).start();
-    } catch (final SchedulerException e) {
-      LOG.error("Error starting cron scheduler", e);
-    }
     LOG.debug("INITIALIZATION DONE!");
   }
 
@@ -181,7 +175,7 @@
 
   private void stopContainerListeners(final List<Class<? extends ContainerListener>> listenerClasses,
       final Injector injector) {
-    LOG.debug("STOPING CONTAINER LISTENERS...");
+    LOG.debug("STOPPING CONTAINER LISTENERS...");
     for (final Class<? extends ContainerListener> listenerClass : listenerClasses) {
       final ContainerListener listener = injector.getInstance(listenerClass);
       listener.stop();

Modified: trunk/src/main/java/cc/kune/core/server/rpc/SocialNetworkRPC.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/rpc/SocialNetworkRPC.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/rpc/SocialNetworkRPC.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -28,7 +28,7 @@
 import cc.kune.core.server.manager.GroupManager;
 import cc.kune.core.server.manager.SocialNetworkManager;
 import cc.kune.core.server.mapper.Mapper;
-import cc.kune.core.server.notifier.NotifyService;
+import cc.kune.core.server.notifier.NotificationService;
 import cc.kune.core.shared.domain.AccessRol;
 import cc.kune.core.shared.domain.utils.StateToken;
 import cc.kune.core.shared.dto.SocialNetworkDataDTO;
@@ -43,14 +43,14 @@
 
   private final GroupManager groupManager;
   private final Mapper mapper;
-  private final NotifyService notifyService;
+  private final NotificationService notifyService;
   private final SocialNetworkManager socialNetworkManager;
   private final UserSessionManager userSessionManager;
 
   @Inject
   public SocialNetworkRPC(final UserSessionManager userSessionManager, final GroupManager groupManager,
       final SocialNetworkManager socialNetworkManager, final Mapper mapper,
-      final NotifyService notifyService) {
+      final NotificationService notifyService) {
     this.userSessionManager = userSessionManager;
     this.groupManager = groupManager;
     this.socialNetworkManager = socialNetworkManager;

Deleted: trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/scheduler/AbstractJob.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,26 +0,0 @@
-package cc.kune.core.server.scheduler;
-
-import static org.quartz.CronScheduleBuilder.cronSchedule;
-import static org.quartz.JobBuilder.newJob;
-import static org.quartz.TriggerBuilder.newTrigger;
-
-import java.text.ParseException;
-
-import org.quartz.CronTrigger;
-import org.quartz.Job;
-import org.quartz.JobDetail;
-import org.quartz.SchedulerException;
-
-public abstract class AbstractJob implements Job {
-  private static final String DEF_GROUP = "groupdef";
-
-  public AbstractJob(final CronServerTasksManager manager, final String cronExpression)
-      throws ParseException, SchedulerException {
-    final JobDetail job = newJob(HourlyJob.class).withIdentity("hourlyjob1", DEF_GROUP).build();
-
-    final CronTrigger trigger = newTrigger().withIdentity("hourlytrigger1", DEF_GROUP).withSchedule(
-        cronSchedule(cronExpression)).build();
-
-    manager.scheduleJob(job, trigger);
-  }
-}

Modified: trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/scheduler/CronServerTasksManager.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,34 +1,77 @@
 package cc.kune.core.server.scheduler;
 
+import static org.quartz.CronScheduleBuilder.cronSchedule;
+import static org.quartz.JobBuilder.newJob;
+import static org.quartz.TriggerBuilder.newTrigger;
+
+import java.text.ParseException;
 import java.util.Date;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.quartz.CronTrigger;
+import org.quartz.Job;
 import org.quartz.JobDetail;
 import org.quartz.Scheduler;
 import org.quartz.SchedulerException;
 import org.quartz.impl.StdSchedulerFactory;
 
+import cc.kune.core.server.notifier.PendingNotificationDailyJob;
+import cc.kune.core.server.notifier.PendingNotificationHourlyJob;
+import cc.kune.core.server.notifier.PendingNotificationImmediateJob;
+import cc.kune.core.server.rack.ContainerListener;
+
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
 @Singleton
-public class CronServerTasksManager {
+public class CronServerTasksManager implements ContainerListener {
+  private static final String DEF_GROUP = "groupdef";
+  public static final Log LOG = LogFactory.getLog(CronServerTasksManager.class);
   private final Scheduler sched;
 
   @Inject
-  public CronServerTasksManager(final StdSchedulerFactory sf) throws SchedulerException {
+  public CronServerTasksManager(final StdSchedulerFactory sf, final CustomJobFactory jobFactory)
+      throws SchedulerException {
     sched = sf.getScheduler();
+    sched.setJobFactory(jobFactory);
   }
 
-  public Date scheduleJob(final JobDetail job, final CronTrigger trigger) throws SchedulerException {
+  private void logError(final Exception e) {
+    LOG.error("Error starting cron scheduler", e);
+  }
+
+  public Date scheduleJob(final Class<? extends Job> jobClass, final String cronExpression,
+      final String identify) throws SchedulerException, ParseException {
+    final JobDetail job = newJob(jobClass).withIdentity(identify + "job", DEF_GROUP).build();
+    final CronTrigger trigger = newTrigger().withIdentity(identify + "trigger", DEF_GROUP).withSchedule(
+        cronSchedule(cronExpression)).startNow().build();
     return sched.scheduleJob(job, trigger);
   }
 
-  public void start() throws SchedulerException {
-    sched.start();
+  @Override
+  public void start() {
+    LOG.info("Starting cron manager");
+    try {
+
+      sched.start();
+      scheduleJob(PendingNotificationImmediateJob.class, "0 */2 * * * ?", "pendinnotifimmediate");
+      scheduleJob(PendingNotificationHourlyJob.class, "0 0 * * * ?", "pendingnotifhourly");
+      scheduleJob(PendingNotificationDailyJob.class, "0 5 0 * * ?", "pendingnotifdaily");
+    } catch (final SchedulerException e) {
+      logError(e);
+    } catch (final ParseException e) {
+      logError(e);
+    }
   }
 
-  public void stop() throws SchedulerException {
-    sched.shutdown(true);
+  @Override
+  public void stop() {
+    LOG.info("Stopping cron manager");
+    try {
+      sched.shutdown(true);
+    } catch (final SchedulerException e) {
+      logError(e);
+    }
   }
 }

Added: trunk/src/main/java/cc/kune/core/server/scheduler/CustomJobFactory.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/scheduler/CustomJobFactory.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/core/server/scheduler/CustomJobFactory.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,31 @@
+package cc.kune.core.server.scheduler;
+
+import org.quartz.Job;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.spi.JobFactory;
+import org.quartz.spi.TriggerFiredBundle;
+
+import com.google.inject.Injector;
+import com.google.inject.Singleton;
+
+/**
+ * A factory for creating CustomJob objects. See:
+ * http://javaeenotes.blogspot.com
+ * /2011/09/inject-instances-in-quartz-jobs-with.html
+ */
+ at Singleton
+public class CustomJobFactory implements JobFactory {
+
+  private Injector injector;
+
+  @Override
+  public Job newJob(final TriggerFiredBundle bundle, final Scheduler scheduler)
+      throws SchedulerException {
+    return injector.getInstance(bundle.getJobDetail().getJobClass());
+  }
+
+  public void setInjector(final Injector injector) {
+    this.injector = injector;
+  }
+}
\ No newline at end of file

Deleted: trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/scheduler/DailyJob.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,13 +0,0 @@
-package cc.kune.core.server.scheduler;
-
-import java.text.ParseException;
-
-import org.quartz.SchedulerException;
-
-public abstract class DailyJob extends AbstractJob {
-
-  public DailyJob(final CronServerTasksManager manager) throws ParseException, SchedulerException {
-    super(manager, "0 0 * * * ?");
-  }
-
-}

Deleted: trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java
===================================================================
--- trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/core/server/scheduler/HourlyJob.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,13 +0,0 @@
-package cc.kune.core.server.scheduler;
-
-import java.text.ParseException;
-
-import org.quartz.SchedulerException;
-
-public abstract class HourlyJob extends AbstractJob {
-
-  public HourlyJob(final CronServerTasksManager manager) throws ParseException, SchedulerException {
-    super(manager, "0 * * * * ?");
-  }
-
-}

Modified: trunk/src/main/java/cc/kune/gspace/client/options/general/UserOptGeneralPresenter.java
===================================================================
--- trunk/src/main/java/cc/kune/gspace/client/options/general/UserOptGeneralPresenter.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/gspace/client/options/general/UserOptGeneralPresenter.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -111,7 +111,6 @@
                   });
             };
           }
-
       );
     }
   }

Modified: trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java
===================================================================
--- trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/lists/server/ListsServerTool.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -44,7 +44,7 @@
 import cc.kune.domain.Content;
 import cc.kune.domain.Group;
 import cc.kune.domain.User;
-import cc.kune.wave.server.KuneWaveUtils;
+import cc.kune.wave.server.KuneWaveServerUtils;
 import cc.kune.wave.server.kspecific.KuneWaveService;
 
 import com.google.inject.Inject;
@@ -91,7 +91,7 @@
     }
     members.add(getUserGroup().getShortName());
     Collections.sort(members);
-    waveManager.addParticipants(KuneWaveUtils.getWaveRef(content),
+    waveManager.addParticipants(KuneWaveServerUtils.getWaveRef(content),
         content.getAuthors().get(0).getShortName(), getUserGroup().getShortName(),
         members.toArray(new String[members.size()]));
   }

Copied: trunk/src/main/java/cc/kune/wave/server/KuneWaveServerUtils.java (from rev 1655, trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java)
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveServerUtils.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveServerUtils.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,76 @@
+/*
+ *
+ * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
+ * This file is part of kune.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package cc.kune.wave.server;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.NoResultException;
+
+import org.waveprotocol.wave.model.waveref.InvalidWaveRefException;
+import org.waveprotocol.wave.model.waveref.WaveRef;
+import org.waveprotocol.wave.util.escapers.jvm.JavaWaverefEncoder;
+
+import cc.kune.core.client.errors.DefaultException;
+import cc.kune.domain.Content;
+import cc.kune.domain.User;
+import cc.kune.domain.finders.UserFinder;
+import cc.kune.wave.server.kspecific.KuneWaveService;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.google.wave.api.Participants;
+
+public class KuneWaveServerUtils {
+
+  @Inject
+  static Provider<ParticipantUtils> participantUtils;
+  @Inject
+  static Provider<UserFinder> userFinder;
+  @Inject
+  static Provider<KuneWaveService> waveService;
+
+  public static Collection<User> getLocalParticipants(final WaveRef waveref, final String author) {
+    final Participants participants = waveService.get().getParticipants(waveref, author);
+    final Set<User> list = new HashSet<User>();
+    for (final String participant : participants) {
+      participantUtils.get().isLocal(participant);
+      try {
+        list.add(userFinder.get().findByShortName(participantUtils.get().getAddressName(participant)));
+      } catch (final NoResultException e) {
+        // Seems is not a local user
+      }
+    }
+    return list;
+  }
+
+  public static String getUrl(final WaveRef waveref) {
+    return JavaWaverefEncoder.encodeToUriPathSegment(waveref);
+  }
+
+  public static WaveRef getWaveRef(final Content content) {
+    try {
+      return JavaWaverefEncoder.decodeWaveRefFromPath(String.valueOf(content.getWaveId()));
+    } catch (final InvalidWaveRefException e) {
+      throw new DefaultException("Error getting the wave");
+    }
+  }
+}

Deleted: trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/wave/server/KuneWaveUtils.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,41 +0,0 @@
-/*
- *
- * Copyright (C) 2007-2011 The kune development team (see CREDITS for details)
- * This file is part of kune.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package cc.kune.wave.server;
-
-import org.waveprotocol.wave.model.waveref.InvalidWaveRefException;
-import org.waveprotocol.wave.model.waveref.WaveRef;
-import org.waveprotocol.wave.util.escapers.jvm.JavaWaverefEncoder;
-
-import cc.kune.core.client.errors.DefaultException;
-import cc.kune.domain.Content;
-
-public class KuneWaveUtils {
-  public static String getUrl(final WaveRef waveref) {
-    return JavaWaverefEncoder.encodeToUriPathSegment(waveref);
-  }
-
-  public static WaveRef getWaveRef(final Content content) {
-    try {
-      return JavaWaverefEncoder.decodeWaveRefFromPath(String.valueOf(content.getWaveId()));
-    } catch (final InvalidWaveRefException e) {
-      throw new DefaultException("Error getting the wave");
-    }
-  }
-}

Modified: trunk/src/main/java/cc/kune/wave/server/kspecific/KuneAgent.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/kspecific/KuneAgent.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/wave/server/kspecific/KuneAgent.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -34,6 +34,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.google.inject.Singleton;
+import com.google.wave.api.Participants;
 import com.google.wave.api.Wavelet;
 
 @SuppressWarnings("serial")
@@ -145,6 +146,12 @@
   }
 
   @Override
+  public Participants getParticipants(final WaveRef waveref, final String author) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
   public String getRobotId() {
     return "kune-agent";
   }
@@ -160,6 +167,12 @@
   }
 
   @Override
+  public String getTitle(final WaveRef waveName, final String author) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
   public boolean isParticipant(final Wavelet wavelet, final String user) {
     // TODO Auto-generated method stub
     return false;

Modified: trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveService.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveService.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveService.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -26,6 +26,7 @@
 import org.waveprotocol.wave.model.wave.ParticipantId;
 import org.waveprotocol.wave.model.waveref.WaveRef;
 
+import com.google.wave.api.Participants;
 import com.google.wave.api.Wavelet;
 
 public interface KuneWaveService {
@@ -54,6 +55,10 @@
 
   Wavelet fetchWave(WaveRef waveRef, String author);
 
+  Participants getParticipants(WaveRef waveref, String author);
+
+  String getTitle(WaveRef waveName, String author);
+
   boolean isParticipant(Wavelet wavelet, String user);
 
   String render(Wavelet wavelet);
@@ -64,5 +69,4 @@
       String someValue);
 
   void setTitle(WaveRef waveName, String title, String author);
-
 }

Modified: trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveServiceDefault.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveServiceDefault.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/wave/server/kspecific/KuneWaveServiceDefault.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -419,6 +419,17 @@
   }
 
   @Override
+  public Participants getParticipants(final WaveRef waveref, final String author) {
+    return fetchWave(waveref, author).getParticipants();
+  }
+
+  @Override
+  public String getTitle(final WaveRef waveName, final String author) {
+    final Wavelet wavelet = fetchWave(waveName, author);
+    return wavelet.getTitle();
+  }
+
+  @Override
   public boolean isParticipant(final Wavelet wavelet, final String user) {
     return wavelet.getParticipants().contains(participantUtils.of(user).toString());
   }

Deleted: trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,83 +0,0 @@
-package cc.kune.wave.server.kspecific;
-
-import javax.persistence.NoResultException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.waveprotocol.box.common.DeltaSequence;
-import org.waveprotocol.box.server.waveserver.WaveBus;
-import org.waveprotocol.box.server.waveserver.WaveBus.Subscriber;
-import org.waveprotocol.wave.model.id.IdUtil;
-import org.waveprotocol.wave.model.id.WaveletId;
-import org.waveprotocol.wave.model.id.WaveletName;
-import org.waveprotocol.wave.model.operation.wave.AddParticipant;
-import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta;
-import org.waveprotocol.wave.model.operation.wave.WaveletBlipOperation;
-import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
-import org.waveprotocol.wave.model.version.HashedVersion;
-import org.waveprotocol.wave.model.wave.ParticipantId;
-import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
-import org.waveprotocol.wave.model.waveref.WaveRef;
-
-import cc.kune.core.server.LogThis;
-import cc.kune.core.server.mail.FormatedString;
-import cc.kune.core.server.notifier.NotifySender;
-import cc.kune.core.server.notifier.NotifyType;
-import cc.kune.core.server.properties.KuneBasicProperties;
-import cc.kune.domain.User;
-import cc.kune.domain.finders.UserFinder;
-import cc.kune.wave.server.KuneWaveUtils;
-import cc.kune.wave.server.ParticipantUtils;
-
-import com.google.inject.Inject;
-
- at LogThis
-public class WaveEmailNotifier {
-  public static final Log LOG = LogFactory.getLog(WaveEmailNotifier.class);
-
-  @Inject
-  public WaveEmailNotifier(final WaveBus waveBus, final NotifySender notifyService,
-      final KuneBasicProperties basicProperties, final ParticipantUtils partUtils,
-      final UserFinder userFinder) {
-    waveBus.subscribe(new Subscriber() {
-      @Override
-      public void waveletCommitted(final WaveletName waveletName, final HashedVersion version) {
-      }
-
-      @Override
-      public void waveletUpdate(final ReadableWaveletData wavelet, final DeltaSequence deltas) {
-        final WaveletId waveletId = wavelet.getWaveletId();
-        if (IdUtil.isUserDataWavelet(waveletId)) {
-          return;
-        }
-        for (final TransformedWaveletDelta delta : deltas) {
-          for (final WaveletOperation op : delta) {
-            if (op instanceof AddParticipant) {
-              final ParticipantId participant = ((AddParticipant) op).getParticipantId();
-              final String url = KuneWaveUtils.getUrl(WaveRef.of(wavelet.getWaveId(), waveletId));
-              final FormatedString body = FormatedString.build(
-                  "Hi there,<br><br>You have a new message in %s. <a href=\"%s#%s\">Read more</a>.<br>",
-                  basicProperties.getSiteCommonName(), basicProperties.getSiteUrl(), url);
-              final String address = participant.getAddress();
-              if (partUtils.isLocal(address)) {
-                final String userName = partUtils.getAddressName(address);
-                try {
-                  final User user = userFinder.findByShortName(userName);
-                  notifyService.send(NotifyType.email, FormatedString.build("You have a new message"),
-                      body, true, false, user);
-                  // notifyService.send(NotifyType.chat,
-                  // FormatedString.build("New message"), body, true,
-                  // user);
-                } catch (final NoResultException e) {
-                  // Seems is not a local user
-                }
-              }
-            } else if (op instanceof WaveletBlipOperation) {
-
-            }
-          }
-        }
-      }
-    });
-  }
-}

Added: trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java
===================================================================
--- trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java	                        (rev 0)
+++ trunk/src/main/java/cc/kune/wave/server/kspecific/WaveEmailNotifier.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,153 @@
+package cc.kune.wave.server.kspecific;
+
+import java.util.HashSet;
+
+import javax.persistence.NoResultException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.waveprotocol.box.common.DeltaSequence;
+import org.waveprotocol.box.server.waveserver.WaveBus;
+import org.waveprotocol.box.server.waveserver.WaveBus.Subscriber;
+import org.waveprotocol.wave.model.id.IdUtil;
+import org.waveprotocol.wave.model.id.WaveId;
+import org.waveprotocol.wave.model.id.WaveletId;
+import org.waveprotocol.wave.model.id.WaveletName;
+import org.waveprotocol.wave.model.operation.wave.AddParticipant;
+import org.waveprotocol.wave.model.operation.wave.RemoveParticipant;
+import org.waveprotocol.wave.model.operation.wave.TransformedWaveletDelta;
+import org.waveprotocol.wave.model.operation.wave.WaveletBlipOperation;
+import org.waveprotocol.wave.model.operation.wave.WaveletOperation;
+import org.waveprotocol.wave.model.version.HashedVersion;
+import org.waveprotocol.wave.model.wave.ParticipantId;
+import org.waveprotocol.wave.model.wave.data.ReadableWaveletData;
+import org.waveprotocol.wave.model.waveref.WaveRef;
+
+import cc.kune.core.client.state.SiteTokens;
+import cc.kune.core.server.LogThis;
+import cc.kune.core.server.mail.FormatedString;
+import cc.kune.core.server.notifier.NotificationType;
+import cc.kune.core.server.notifier.PendingNotification;
+import cc.kune.core.server.notifier.PendingNotificationSender;
+import cc.kune.core.server.notifier.SimpleDestinationProvider;
+import cc.kune.core.server.notifier.WaveDestinationProvider;
+import cc.kune.core.server.properties.KuneBasicProperties;
+import cc.kune.core.server.rack.ContainerListener;
+import cc.kune.domain.User;
+import cc.kune.domain.finders.UserFinder;
+import cc.kune.wave.server.KuneWaveServerUtils;
+import cc.kune.wave.server.ParticipantUtils;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+ at LogThis
+ at Singleton
+public class WaveEmailNotifier implements ContainerListener {
+  public static final Log LOG = LogFactory.getLog(WaveEmailNotifier.class);
+  private HashSet<WaveId> updatedWavesInLastHour;
+
+  @Inject
+  public WaveEmailNotifier(final WaveBus waveBus, final PendingNotificationSender notificator,
+      final KuneBasicProperties basicProperties, final ParticipantUtils partUtils,
+      final KuneWaveService waveService, final UserFinder userFinder) {
+
+    final String siteCommonName = basicProperties.getSiteCommonName();
+    final String siteUrl = basicProperties.getSiteUrl();
+    updatedWavesInLastHour = new HashSet<WaveId>();
+    waveBus.subscribe(new Subscriber() {
+
+      private void addPendingNotif(final ParticipantId participant, final FormatedString subject,
+          final FormatedString body) {
+        final String address = participant.getAddress();
+        if (partUtils.isLocal(address)) {
+          final String userName = partUtils.getAddressName(address);
+          try {
+            final User user = userFinder.findByShortName(userName);
+            notificator.add(new PendingNotification(NotificationType.email, subject, body, true, false,
+                new SimpleDestinationProvider(user)));
+          } catch (final NoResultException e) {
+            // Seems is not a local user
+          }
+        }
+      }
+
+      private String getUrl(final ReadableWaveletData wavelet, final WaveletId waveletId) {
+        return KuneWaveServerUtils.getUrl(WaveRef.of(wavelet.getWaveId(), waveletId));
+      }
+
+      private FormatedString newWaveTemplate(final String url) {
+        return FormatedString.build(
+            "Hi there,<br><br>You have a new message in your inbox at %s. <a href=\"%s#%s\">Read more</a>.<br>",
+            siteCommonName, siteUrl, url);
+      }
+
+      private FormatedString removeWaveTemplate(final String by, final String title) {
+        return FormatedString.build(
+            "Hi there,<br><br>You have been removed by '%s' from message '%s' at %s. <a href=\"%s#%s\">Read more</a>.<br>",
+            by, title, siteCommonName, siteUrl, SiteTokens.WAVEINBOX);
+      }
+
+      private FormatedString updatedWaveTemplate(final String by, final String url) {
+        return FormatedString.build(
+            "Hi there,<br><br>You have an updated message by '%s' in your inbox at %s. <a href=\"%s#%s\">Read more</a>.<br>",
+            by, siteCommonName, siteUrl, url);
+      }
+
+      @Override
+      public void waveletCommitted(final WaveletName waveletName, final HashedVersion version) {
+      }
+
+      @Override
+      public void waveletUpdate(final ReadableWaveletData wavelet, final DeltaSequence deltas) {
+        final WaveletId waveletId = wavelet.getWaveletId();
+        if (IdUtil.isUserDataWavelet(waveletId)) {
+          return;
+        }
+        for (final TransformedWaveletDelta delta : deltas) {
+          for (final WaveletOperation op : delta) {
+            if (op instanceof AddParticipant) {
+              final ParticipantId participant = ((AddParticipant) op).getParticipantId();
+              addPendingNotif(participant, FormatedString.build("You have a new message"),
+                  newWaveTemplate(getUrl(wavelet, waveletId)));
+            } else if (op instanceof RemoveParticipant) {
+              final ParticipantId participant = ((RemoveParticipant) op).getParticipantId();
+              final ParticipantId by = ((RemoveParticipant) op).getContext().getCreator();
+              final String title = waveService.getTitle(WaveRef.of(wavelet.getWaveId(), waveletId),
+                  by.toString());
+              addPendingNotif(participant, FormatedString.build("You have been removed from message"),
+                  removeWaveTemplate(by.toString(), title));
+            } else if (op instanceof WaveletBlipOperation) {
+              final WaveId waveId = wavelet.getWaveId();
+              if (!updatedWavesInLastHour.contains(waveId)) {
+                updatedWavesInLastHour.add(waveId);
+                // Replies, etc
+                final ParticipantId by = ((WaveletBlipOperation) op).getContext().getCreator();
+                // Duplicate code above
+                final WaveRef waveref = WaveRef.of(waveId, waveletId);
+                final String url = KuneWaveServerUtils.getUrl(waveref);
+                notificator.add(new PendingNotification(NotificationType.email,
+                    FormatedString.build("You have an updated message"), updatedWaveTemplate(
+                        by.toString(), url), true, false, new WaveDestinationProvider(waveref,
+                        by.toString())));
+              }
+            }
+          }
+        }
+      }
+    });
+  }
+
+  public void clearUpdatedWaves() {
+    updatedWavesInLastHour.clear();
+  }
+
+  @Override
+  public void start() {
+  }
+
+  @Override
+  public void stop() {
+  }
+
+}

Added: trunk/src/test/java/cc/kune/core/server/notifier/AbstractPendingNotificationTest.java
===================================================================
--- trunk/src/test/java/cc/kune/core/server/notifier/AbstractPendingNotificationTest.java	                        (rev 0)
+++ trunk/src/test/java/cc/kune/core/server/notifier/AbstractPendingNotificationTest.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,32 @@
+package cc.kune.core.server.notifier;
+
+import org.junit.Before;
+
+import cc.kune.core.server.notifier.SimpleDestinationProvider;
+import cc.kune.domain.User;
+
+public abstract class AbstractPendingNotificationTest {
+
+  protected SimpleDestinationProvider diferentProvider;
+  protected User otherDiferentUser;
+  protected User sameUser;
+  protected SimpleDestinationProvider someSimilarUserProvider;
+  protected SimpleDestinationProvider someSimilarUserProvider2;
+  protected SimpleDestinationProvider someUserProvider;
+  protected User user;
+
+  @Before
+  public void before() {
+    user = new User("test1", "test1 name", "falseEmail@", "some passwd", "somediggest".getBytes(),
+        "some salt".getBytes(), null, null, null);
+    sameUser = new User("test1", "test1 name", "falseEmail@", "some passwd", "somediggest".getBytes(),
+        "some salt".getBytes(), null, null, null);
+    otherDiferentUser = new User("test2", "test2 name", "falseEmail@", "some passwd",
+        "somediggest".getBytes(), "some salt".getBytes(), null, null, null);
+    someUserProvider = new SimpleDestinationProvider(user);
+    someSimilarUserProvider = new SimpleDestinationProvider(user);
+    someSimilarUserProvider2 = new SimpleDestinationProvider(sameUser);
+    diferentProvider = new SimpleDestinationProvider(otherDiferentUser);
+  }
+
+}

Copied: trunk/src/test/java/cc/kune/core/server/notifier/NotificationHtmlHelperTest.java (from rev 1655, trunk/src/test/java/cc/kune/core/server/notifier/NotifyHtmlHelperTest.java)
===================================================================
--- trunk/src/test/java/cc/kune/core/server/notifier/NotificationHtmlHelperTest.java	                        (rev 0)
+++ trunk/src/test/java/cc/kune/core/server/notifier/NotificationHtmlHelperTest.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,30 @@
+package cc.kune.core.server.notifier;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import cc.kune.core.server.properties.KuneBasicProperties;
+import cc.kune.core.server.properties.KunePropertiesDefault;
+import cc.kune.core.server.utils.AbsoluteFileDownloadUtils;
+
+public class NotificationHtmlHelperTest {
+  private static final String GROUP_NAME = "groupShortName";
+  private static final String MESSAGE = "some message";
+
+  NotificationHtmlHelper helper;
+
+  @Test
+  public void basicTest() {
+    assertNotNull(helper.groupNotification(GROUP_NAME, false, MESSAGE).getString());
+    assertNotNull(helper.groupNotification(GROUP_NAME, true, MESSAGE).getString());
+  }
+
+  @Before
+  public void before() {
+    helper = new NotificationHtmlHelper(new AbsoluteFileDownloadUtils(new KuneBasicProperties(
+        new KunePropertiesDefault("kune.properties"))));
+  }
+
+}

Deleted: trunk/src/test/java/cc/kune/core/server/notifier/NotifyHtmlHelperTest.java
===================================================================
--- trunk/src/test/java/cc/kune/core/server/notifier/NotifyHtmlHelperTest.java	2012-01-09 15:37:06 UTC (rev 1657)
+++ trunk/src/test/java/cc/kune/core/server/notifier/NotifyHtmlHelperTest.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -1,30 +0,0 @@
-package cc.kune.core.server.notifier;
-
-import static org.junit.Assert.assertNotNull;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import cc.kune.core.server.properties.KuneBasicProperties;
-import cc.kune.core.server.properties.KunePropertiesDefault;
-import cc.kune.core.server.utils.AbsoluteFileDownloadUtils;
-
-public class NotifyHtmlHelperTest {
-  private static final String GROUP_NAME = "groupShortName";
-  private static final String MESSAGE = "some message";
-
-  NotifyHtmlHelper helper;
-
-  @Test
-  public void basicTest() {
-    assertNotNull(helper.groupNotification(GROUP_NAME, false, MESSAGE).getString());
-    assertNotNull(helper.groupNotification(GROUP_NAME, true, MESSAGE).getString());
-  }
-
-  @Before
-  public void before() {
-    helper = new NotifyHtmlHelper(new AbsoluteFileDownloadUtils(new KuneBasicProperties(
-        new KunePropertiesDefault("kune.properties"))));
-  }
-
-}

Added: trunk/src/test/java/cc/kune/core/server/notifier/PendingNotificationSenderTest.java
===================================================================
--- trunk/src/test/java/cc/kune/core/server/notifier/PendingNotificationSenderTest.java	                        (rev 0)
+++ trunk/src/test/java/cc/kune/core/server/notifier/PendingNotificationSenderTest.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,85 @@
+package cc.kune.core.server.notifier;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import cc.kune.core.server.mail.FormatedString;
+
+public class PendingNotificationSenderTest extends AbstractPendingNotificationTest {
+
+  private static final FormatedString BODY = FormatedString.build("Some body");
+  private static final FormatedString OTHER_BODY = FormatedString.build("Some other body");
+  private static final FormatedString OTHER_SUBJECT = FormatedString.build("Some other subject");
+  private static final FormatedString SUBJECT = FormatedString.build("Some subject");
+  private PendingNotificationSender manager;
+  private PendingNotification otherNotif;
+  private NotificationSender sender;
+  private PendingNotification someForcedNotif;
+  private PendingNotification someNotif;
+
+  private void assertQueues(final int i, final int j, final int k) {
+    // TODO Auto-generated method stub
+    assertEquals(manager.getImmediateCount(), i);
+    assertEquals(manager.getHourlyCount(), j);
+    assertEquals(manager.getDailyCount(), k);
+  }
+
+  @Override
+  @Before
+  public void before() {
+    sender = Mockito.mock(NotificationSender.class);
+    manager = new PendingNotificationSender(sender);
+    someNotif = new PendingNotification(NotificationType.email, SUBJECT, BODY, false, false,
+        someUserProvider);
+    otherNotif = new PendingNotification(NotificationType.email, OTHER_SUBJECT, OTHER_BODY, false,
+        false, someUserProvider);
+    someForcedNotif = new PendingNotification(NotificationType.email, SUBJECT, BODY, false, true,
+        someUserProvider);
+  }
+
+  @Test
+  public void testForcePendingNotification() {
+    manager.add(someForcedNotif);
+    assertQueues(1, 0, 0);
+    manager.sendImmediateNotifications();
+    assertQueues(0, 0, 0);
+  }
+
+  @Test
+  public void testMixtureOfNotifications() {
+    manager.add(someNotif);
+    manager.add(someForcedNotif);
+    assertQueues(2, 0, 0);
+    manager.sendImmediateNotifications();
+    assertQueues(0, 1, 0);
+  }
+
+  @Test
+  public void testSimplePendingNotification() {
+    manager.add(someNotif);
+    // we add two times (imagine two editions)
+    manager.add(someNotif);
+    manager.add(otherNotif);
+    assertQueues(2, 0, 0);
+    manager.sendImmediateNotifications();
+    assertQueues(0, 2, 0);
+    // we repeat some notification (for instance an edit) and should be ignored
+    manager.add(someNotif);
+    assertQueues(0, 2, 0);
+    manager.sendHourlyNotifications();
+    assertQueues(0, 0, 2);
+    // we repeat some notification (for instance an edit) and should be ignored
+    manager.add(someNotif);
+    assertQueues(1, 0, 2);
+    manager.sendImmediateNotifications();
+    assertQueues(0, 1, 2);
+    manager.sendHourlyNotifications();
+    assertQueues(0, 0, 2);
+    manager.sendDailyNotifications();
+    assertQueues(0, 0, 0);
+  }
+
+}

Added: trunk/src/test/java/cc/kune/core/server/notifier/SimpleDestinationProviderTest.java
===================================================================
--- trunk/src/test/java/cc/kune/core/server/notifier/SimpleDestinationProviderTest.java	                        (rev 0)
+++ trunk/src/test/java/cc/kune/core/server/notifier/SimpleDestinationProviderTest.java	2012-01-12 01:40:41 UTC (rev 1658)
@@ -0,0 +1,18 @@
+package cc.kune.core.server.notifier;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class SimpleDestinationProviderTest extends AbstractPendingNotificationTest {
+
+  @Test
+  public void shouldCompareWell() {
+    assertTrue(someUserProvider.equals(someSimilarUserProvider));
+    assertTrue(someUserProvider.equals(someSimilarUserProvider2));
+    assertTrue(someSimilarUserProvider.equals(someSimilarUserProvider2));
+    assertFalse(someUserProvider.equals(diferentProvider));
+  }
+
+}




More information about the kune-commits mailing list