BrightSide Workbench Full Report + Source Code
QueueManager.java
Go to the documentation of this file.
1 /*
2  * TurrĂ³ i Cutiller Foundation. License notice.
3  * Copyright (C) 2017 Lluis TurrĂ³ Cutiller <http://www.turro.org/>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 package org.turro.mail.queue;
20 
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Date;
24 import java.util.List;
25 import java.util.concurrent.locks.Lock;
26 import java.util.concurrent.locks.ReentrantLock;
27 import org.amic.util.date.CheckDate;
28 import org.turro.action.Contacts;
29 import org.turro.action.queue.ConstraintKeys;
30 import org.turro.string.Strings;
31 import org.turro.action.queue.NotificationCategory;
32 import org.turro.action.queue.Notifications;
33 import org.turro.action.queue.QueuePeriod;
34 import org.turro.elephant.context.IConstructor;
35 import org.turro.elephant.db.ElephantPU;
36 import org.turro.elephant.db.WhereClause;
37 import org.turro.elephant.entities.db.MailItem;
38 import org.turro.elephant.entities.db.QueueOptions;
39 import org.turro.jpa.Dao;
40 import org.turro.mail.message.MailMessage;
41 import org.turro.plugin.contacts.IContact;
42 import org.turro.sql.SqlClause;
43 
48 public class QueueManager {
49 
50  public static void send(IConstructor constructor, QueuePeriod period) {
51  boolean lockAcquired = QUEUEMANAGER_LOCK.tryLock();
52  if(lockAcquired) {
53  try {
54  QueueManager qm = new QueueManager();
56  qm.removeOldsByPeriod();
57  ContactMap cm = qm.getContactMap(qm.getPending(period));
58  for(String idContact : cm.keySet()) {
59  new ContactQueueSender(constructor, qm, period, cm.get(idContact)).send();
60  }
61  } finally {
62  QUEUEMANAGER_LOCK.unlock();
63  }
64  }
65  }
66 
67  public MailItem addToQueue(NotificationCategory category, IContact contact,
68  MailMessage mmt, String reason, String poolName) {
69  if(contact.isWebUser()) {
70  MailItem mi = new MailItem();
71  mi.setIdCategory(category.getIdCategory());
72  mi.setCategory(category.getCategory());
73  mi.setDescription(category.getDescription());
74  mi.setIContact(contact);
75  mi.setItemDate(mmt.getSentDate());
76  mi.setSubject(mmt.getSubject());
77  mi.setMessage(mmt.getMessage());
78  mi.setReason(cleanSubject(reason));
79  mi.setPoolName(poolName);
80  if(category.isUnique()) {
81  removeUniquesFor(category.getIdCategory(), contact.getId());
82  }
83  checkConfiguration(contact, category.getIdCategory(), category.getDefaultPeriod());
84  return getDao().saveObject(mi);
85  }
86  return null;
87  }
88 
89  public MailItem addToQueue(NotificationCategory category, IContact contact,
90  String subject, String message, String reason, String poolName) {
91  if(contact.isWebUser()) {
92  MailItem mi = new MailItem();
93  mi.setIdCategory(category.getIdCategory());
94  mi.setCategory(category.getCategory());
95  mi.setDescription(category.getDescription());
96  mi.setIContact(contact);
97  mi.setItemDate(new Date());
98  mi.setSubject(subject);
99  mi.setMessage(message);
100  mi.setReason(cleanSubject(reason));
101  mi.setPoolName(poolName);
102  if(category.isUnique()) {
103  removeUniquesFor(category.getIdCategory(), contact.getId());
104  }
105  checkConfiguration(contact, category.getIdCategory(), category.getDefaultPeriod());
106  return getDao().saveObject(mi);
107  }
108  return null;
109  }
110 
111  public void checkConfiguration(IContact contact, String idCategory, QueuePeriod queuePeriod) {
112  QueueOptions qo = getConfiguration(contact, idCategory);
113  if(qo == null) {
114  qo = new QueueOptions();
115  qo.setIdCategory(idCategory);
116  qo.setIdContact(contact.getId());
117  qo.setPeriod(queuePeriod);
118  qo.setSingleMail(true);
119  configQueue(qo);
120  }
121  }
122 
123  public void setPeriod(IContact contact, String idCategory, QueuePeriod queuePeriod, boolean override) {
124  QueueOptions qo = getConfiguration(contact, idCategory);
125  if(qo != null && !override) return;
126  if(qo == null) {
127  qo = new QueueOptions();
128  qo.setIdCategory(idCategory);
129  qo.setIdContact(contact.getId());
130  qo.setSingleMail(true);
131  }
132  qo.setPeriod(queuePeriod);
133  configQueue(qo);
134  }
135 
136  public void subscribeDefaults(ConstraintKeys keys) {
138  if(nc.wideBond(keys)) {
139  checkConfiguration(keys.contact(), nc.getIdCategory(), nc.getDefaultPeriod());
140  } else if(!nc.strongBond(keys)) {
141  removeOptions(getConfiguration(keys.contact(), nc.getIdCategory()));
142  }
143  }
144  }
145 
146  public QueueOptions getConfiguration(IContact contact, String idCategory) {
147  WhereClause wc = new WhereClause();
148  wc.addClause("select o from QueueOptions o");
149  wc.addClause("where o.idContact = :idContact");
150  wc.addClause("and o.idCategory = :idCategory");
151  wc.addNamedValue("idContact", contact.getId());
152  wc.addNamedValue("idCategory", idCategory);
153  return (QueueOptions) getDao().getSingleResultOrNull(wc);
154  }
155 
157  return getDao().saveObject(qo);
158  }
159 
160  public boolean contactWants(IContact contact, String idCategory) {
161  QueueOptions qo = getConfiguration(contact, idCategory);
162  return qo != null && !QueuePeriod.DONT_SEND.equals(qo.getPeriod());
163  }
164 
165  public boolean contactMayWant(IContact contact, String idCategory) {
166  QueueOptions qo = getConfiguration(contact, idCategory);
167  return qo == null || !QueuePeriod.DONT_SEND.equals(qo.getPeriod());
168  }
169 
170  public List<MailItem> getPending(QueuePeriod period) {
171  WhereClause wc = new WhereClause();
172  wc.addClause("select m from MailItem m, QueueOptions o");
173  wc.addClause("where o.period = :period");
174  wc.addClause("and m.idContact = o.idContact");
175  wc.addClause("and m.idCategory = o.idCategory");
176  wc.addClause("order by m.idContact, m.idCategory");
177  wc.addNamedValue("period", period);
178  return getDao().getResultList(wc);
179  }
180 
181  public ContactMap getContactMap(List<MailItem> list) {
182  ContactMap cm = new ContactMap();
183  for(MailItem mi : list) {
184  cm.addMailItem(mi);
185  }
186  return cm;
187  }
188 
189  public void removeUniquesFor(String idCategory, String idContact) {
190  WhereClause wc = new WhereClause();
191  wc.addClause("delete from MailItem m");
192  wc.addClause("where m.idContact = :contact");
193  wc.addClause("and m.idCategory = :category");
194  wc.addNamedValue("contact", idContact);
195  wc.addNamedValue("category", idCategory);
196  getDao().executeUpdate(wc);
197  }
198 
199  public void removeMails(QueuePeriod period, String idContact, String idCategory) {
200  WhereClause wc = new WhereClause();
201  wc.addClause("delete from MailItem m");
202  wc.addClause("where m.idContact = :contact");
203  wc.addClause("and m.idCategory = :category");
204  wc.addClause("and exists (");
205  wc.addClause("select o from QueueOptions o");
206  wc.addClause("where o.period = :period");
207  wc.addClause("and m.idContact = o.idContact");
208  wc.addClause("and m.idCategory = o.idCategory");
209  wc.addClause(")");
210  wc.addNamedValue("contact", idContact);
211  wc.addNamedValue("category", idCategory);
212  wc.addNamedValue("period", period);
213  getDao().executeUpdate(wc);
214  }
215 
216  public void removeContactMails(String idContact) {
217  WhereClause wc = new WhereClause();
218  wc.addClause("delete from MailItem m");
219  wc.addClause("where m.idContact = :contact");
220  wc.addNamedValue("contact", idContact);
221  getDao().executeUpdate(wc);
222  }
223 
224  public void removeWithoutOptions() {
225  WhereClause wc = new WhereClause();
226  wc.addClause("delete from MailItem m");
227  wc.addClause("where not exists (");
228  wc.addClause("select o from QueueOptions o");
229  wc.addClause("where m.idContact = o.idContact");
230  wc.addClause("and m.idCategory = o.idCategory");
231  wc.addClause(")");
232  getDao().executeUpdate(wc);
233  }
234 
235  public void removeOldsByPeriod() {
236  WhereClause wc = new WhereClause();
237  wc.addClause("delete from MailItem m");
238  wc.addClause("where exists (");
239  wc.addClause("select o from QueueOptions o");
240  wc.addClause("where m.idContact = o.idContact");
241  wc.addClause("and m.idCategory = o.idCategory");
242  wc.addClause("and (");
243  wc.addClause("o.period = :dontSend");
244  wc.addClause("or (o.period = :asGenerated and m.itemDate < :oneDay)");
245  wc.addClause("or (o.period = :daily and m.itemDate < :oneDay)");
246  wc.addClause("or (o.period = :weekly and m.itemDate < :oneWeek)");
247  wc.addClause("or (o.period = :fortnightly and m.itemDate < :twoWeeks)");
248  wc.addClause("or (o.period = :monthly and m.itemDate < :oneMonth)");
249  wc.addClause("or (o.period = :quarterly and m.itemDate < :threeMonths)");
250  wc.addClause("or (o.period = :everySix and m.itemDate < :sixMonths)");
251  wc.addClause("or (o.period = :yearly and m.itemDate < :oneYear)");
252  wc.addClause("))");
253  wc.addNamedValue("dontSend", QueuePeriod.DONT_SEND);
254  wc.addNamedValue("asGenerated", QueuePeriod.AS_GENERATED);
255  wc.addNamedValue("daily", QueuePeriod.DAILY);
256  wc.addNamedValue("oneDay", new CheckDate().addDays(-2).getDate());
257  wc.addNamedValue("weekly", QueuePeriod.WEEKLY);
258  wc.addNamedValue("oneWeek", new CheckDate().addWeeks(-1).addDays(-2).getDate());
259  wc.addNamedValue("fortnightly", QueuePeriod.FORTNIGHTLY);
260  wc.addNamedValue("twoWeeks", new CheckDate().addWeeks(-2).addDays(-2).getDate());
261  wc.addNamedValue("monthly", QueuePeriod.MONTHLY);
262  wc.addNamedValue("oneMonth", new CheckDate().addMonths(-1).addDays(-2).getDate());
263  wc.addNamedValue("quarterly", QueuePeriod.QUARTERLY);
264  wc.addNamedValue("threeMonths", new CheckDate().addMonths(-3).addDays(-2).getDate());
266  wc.addNamedValue("sixMonths", new CheckDate().addMonths(-6).addDays(-2).getDate());
267  wc.addNamedValue("yearly", QueuePeriod.YEARLY);
268  wc.addNamedValue("oneYear", new CheckDate().addYears(-1).addDays(-2).getDate());
269  getDao().executeUpdate(wc);
270  }
271 
272  public void removeOptions(String idCategory) {
273  WhereClause wc = new WhereClause();
274  wc.addClause("delete from QueueOptions o");
275  wc.addClause("where o.idCategory = :category");
276  wc.addNamedValue("category", idCategory);
277  getDao().executeUpdate(wc);
278  }
279 
280  public void setPeriodToAll(String idCategory, QueuePeriod period) {
281  WhereClause wc = new WhereClause();
282  wc.addClause("update QueueOptions o");
283  wc.addClause("set o.period = :period");
284  wc.addClause("where o.idCategory = :category");
285  wc.addNamedValue("period", period);
286  wc.addNamedValue("category", idCategory);
287  getDao().executeUpdate(wc);
288  }
289 
290  public void checkConstraints(String idCategory) {
292  if(nc.getConstraints().isRestricted()) {
293  List<QueueOptions> toDelete = new ArrayList<>();
294  SqlClause.select("o").from("QueueOptions o")
295  .where().equal("o.idCategory", idCategory)
296  .dao(getDao())
297  .resultList(QueueOptions.class)
298  .forEach(o -> {
299  IContact contact = Contacts.getContactById(o.getIdContact());
300  if(contact.isValid()) {
301  ConstraintKeys keys = ConstraintKeys.from(contact);
302  if(!nc.strongBond(keys)) {
303  toDelete.add(o);
304  //removeOptions(getConfiguration(keys.contact(), nc.getIdCategory()));
305  }
306  } else {
307  toDelete.add(o);
308  }
309  });
310  getDao().deleteCollection(toDelete);
311  }
312  }
313 
314  public Collection<QueueOptions> getSubcribers(String idCategory) {
315  WhereClause wc = new WhereClause();
316  wc.addClause("select o from QueueOptions o");
317  wc.addClause("where o.idCategory = :category");
318  wc.addNamedValue("category", idCategory);
319  return getDao().getResultList(wc);
320  }
321 
322  public Collection<Long> getSubcribersId(String idCategory) {
323  WhereClause wc = new WhereClause();
324  wc.addClause("select o.id from QueueOptions o");
325  wc.addClause("where o.idCategory = :category");
326  wc.addNamedValue("category", idCategory);
327  return getDao().getResultList(wc);
328  }
329 
330  public void createBulk() {
331 // IContact contact = Contacts.getContactByEmail("lluis@turro.org");
332 // if(contact != null && contact.isWebUser()) {
333 // QueueOptions qo = new QueueOptions();
334 // qo.setIdCategory("/myissues");
335 // qo.setIdContact(contact.getId());
336 // qo.setPeriod(QueuePeriod.AS_GENERATED);
337 // qo.setSingleMail(true);
338 // configQueue(qo);
339 // MailItem mi = new MailItem();
340 // mi.setIdCategory("/myissues");
341 // mi.setIContact(contact);
342 // mi.setDescription("cosa");
343 // mi.setCategory("My issues");
344 // mi.setItemDate(new Date());
345 // mi.setMessage("Message");
346 // mi.setSubject("Subject");
347 // mi.setPoolName("Dossier");
348 // addToQueue(mi);
349 // }
350  }
351 
352  public void removeMail(MailItem mi) {
353  getDao().deleteObject(mi);
354  }
355 
356  public void removeOptions(QueueOptions qo) {
357  if(qo != null) getDao().deleteObject(qo);
358  }
359 
360  private String cleanSubject(String reason) {
361  if(Strings.isBlank(reason)) {
362  return reason;
363  } else {
364  int p = reason.indexOf(":");
365  return (p > -1 ? reason.substring(0, p) : reason);
366  }
367  }
368 
369  /* Migration tools */
370 
371  public Collection<QueueOptions> getSubcribersByRoot(String root) {
372  WhereClause wc = new WhereClause();
373  wc.addClause("select o from QueueOptions o");
374  wc.addClause("where o.idCategory like :category");
375  wc.addNamedValue("category", root + "/%");
376  return getDao().getResultList(wc);
377  }
378 
379  /* Dao */
380 
381  private Dao _dao;
382 
383  private Dao getDao() {
384  if(_dao == null) {
385  _dao = new ElephantPU();
386  }
387  return _dao;
388  }
389 
390  /* Lock */
391 
392  private static final Lock QUEUEMANAGER_LOCK = new ReentrantLock();
393 
394 }
static IContact getContactById(String id)
Definition: Contacts.java:72
static NotificationCategory getCategory(String id)
static Collection< NotificationCategory > getCategories()
void addNamedValue(String name, Object value)
void setIContact(IContact contact)
Definition: MailItem.java:190
void setDescription(String description)
Definition: MailItem.java:127
void setIdCategory(String idCategory)
Definition: MailItem.java:111
int executeUpdate(String query)
Definition: Dao.java:463
void deleteCollection(Collection objs)
Definition: Dao.java:175
Object getSingleResultOrNull(SqlClause sc)
Definition: Dao.java:419
void addMailItem(MailItem mi)
Definition: ContactMap.java:30
static void send(IConstructor constructor, QueuePeriod period)
void removeMails(QueuePeriod period, String idContact, String idCategory)
void setPeriod(IContact contact, String idCategory, QueuePeriod queuePeriod, boolean override)
QueueOptions configQueue(QueueOptions qo)
void checkConfiguration(IContact contact, String idCategory, QueuePeriod queuePeriod)
QueueOptions getConfiguration(IContact contact, String idCategory)
void removeOptions(QueueOptions qo)
MailItem addToQueue(NotificationCategory category, IContact contact, MailMessage mmt, String reason, String poolName)
List< MailItem > getPending(QueuePeriod period)
Collection< QueueOptions > getSubcribersByRoot(String root)
void removeContactMails(String idContact)
void setPeriodToAll(String idCategory, QueuePeriod period)
void removeOptions(String idCategory)
void checkConstraints(String idCategory)
ContactMap getContactMap(List< MailItem > list)
boolean contactWants(IContact contact, String idCategory)
MailItem addToQueue(NotificationCategory category, IContact contact, String subject, String message, String reason, String poolName)
void subscribeDefaults(ConstraintKeys keys)
Collection< QueueOptions > getSubcribers(String idCategory)
boolean contactMayWant(IContact contact, String idCategory)
Collection< Long > getSubcribersId(String idCategory)
void removeUniquesFor(String idCategory, String idContact)