source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/BerryBasket.java@ 31729

Last change on this file since 31729 was 31729, checked in by kjdon, 7 years ago

modified to use tls or ssl to send mail if requested

  • Property svn:keywords set to Author Date Id Revision
File size: 20.9 KB
Line 
1/*
2 * BerryBasket.java
3 * Copyright (C) 2006 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 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 General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20package org.greenstone.gsdl3.service;
21
22import java.sql.Statement;
23import java.util.Hashtable;
24import java.util.HashMap;
25import java.util.ArrayList;
26import java.util.HashSet;
27import java.util.Iterator;
28
29import org.w3c.dom.Document;
30import org.w3c.dom.Element;
31import org.w3c.dom.NodeList;
32
33import org.greenstone.util.GlobalProperties;
34import org.greenstone.gsdl3.util.GSXML;
35import org.greenstone.gsdl3.util.GSPath;
36import org.greenstone.gsdl3.util.UserContext;
37import org.greenstone.gsdl3.util.XMLConverter;
38
39import java.io.Serializable;
40import java.net.InetAddress;
41import java.util.Properties;
42import java.util.Date;
43
44import javax.mail.*;
45import javax.mail.internet.*;
46
47import java.awt.event.ActionEvent;
48import java.awt.event.ActionListener;
49import javax.swing.Timer;
50
51import org.apache.log4j.*;
52
53public class BerryBasket extends ServiceRack
54{
55
56 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.BerryBasket.class.getName());
57
58 // the services on offer
59 // these strings must match what is found in the properties file
60 protected static final String ADD_ITEM_SERVICE = "AddItem";
61 protected static final String DISPLAY_ITEMS_SERVICE = "DisplayList";
62 protected static final String ITEM_NUM_SERVICE = "ItemNum";
63 protected static final String DELETE_ITEMS_SERVICE = "DeleteItems";
64 protected static final String SEND_MAIL_SERVICE = "SendMail";
65 protected static final String DELETE_ITEM_SERVICE = "DeleteItem";
66
67 protected static final String ITEM_PARAM = "item";
68 protected static final String delimiter = "|";
69 protected static final int delay = 1800000;
70
71 protected Hashtable<String, Hashtable<String, Hashtable<String, Item>>> userMap = null;
72 protected Hashtable<String, UserTimer> timerMap = null;
73 protected String username = "";
74 protected String password = "";
75
76 /** constructor */
77 public BerryBasket()
78 {
79 userMap = new Hashtable<String, Hashtable<String, Hashtable<String, Item>>>();
80 timerMap = new Hashtable<String, UserTimer>();
81 }
82
83 private Hashtable<String, Hashtable<String, Item>> updateDocMap(Element request)
84 {
85
86 String id = request.getAttribute("uid");
87
88 if (userMap.containsKey(id))
89 {
90 if (timerMap.containsKey(id))
91 {
92 UserTimer timer = timerMap.get(id);
93 timer.restart();
94 }
95 return userMap.get(id);
96 }
97 else
98 {
99 UserTimer timer = new UserTimer(delay, id);
100 timerMap.put(id, timer);
101 timer.start();
102 Hashtable<String, Hashtable<String, Item>> newDocs = new Hashtable<String, Hashtable<String, Item>>();
103 userMap.put(id, newDocs);
104 return newDocs;
105 }
106 }
107
108 /** configure this service */
109 public boolean configure(Element info, Element extra_info)
110 {
111 logger.info("Configuring BerryBasket...");
112 this.config_info = info;
113
114 // set up short_service_info_ - for now just has name and type
115 Element add_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
116 add_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
117 add_service.setAttribute(GSXML.NAME_ATT, ADD_ITEM_SERVICE);
118 this.short_service_info.appendChild(add_service);
119
120 // set up short_service_info_ - for now just has name and type
121 Element disp_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
122 disp_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
123 disp_service.setAttribute(GSXML.NAME_ATT, DISPLAY_ITEMS_SERVICE);
124 this.short_service_info.appendChild(disp_service);
125
126 // set up short_service_info_ - for now just has name and type
127 Element num_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
128 num_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
129 num_service.setAttribute(GSXML.NAME_ATT, ITEM_NUM_SERVICE);
130 this.short_service_info.appendChild(num_service);
131
132 // set up short_service_info_ - for now just has name and type
133 Element delete_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
134 delete_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
135 delete_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEMS_SERVICE);
136 this.short_service_info.appendChild(delete_service);
137
138 // set up short_service_info_ - for now just has name and type
139 Element deleteone_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
140 deleteone_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
141 deleteone_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEM_SERVICE);
142 this.short_service_info.appendChild(deleteone_service);
143
144 // set up short_service_info_ - for now just has name and type
145 Element mail_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
146 mail_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
147 mail_service.setAttribute(GSXML.NAME_ATT, SEND_MAIL_SERVICE);
148 this.short_service_info.appendChild(mail_service);
149
150 return true;
151
152 }
153
154 /** returns a specific service description */
155 protected Element getServiceDescription(Document doc, String service_id, String lang, String subset)
156 {
157
158 if (service_id.equals(ADD_ITEM_SERVICE))
159 {
160 Element add_service = doc.createElement(GSXML.SERVICE_ELEM);
161 add_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
162 add_service.setAttribute(GSXML.NAME_ATT, ADD_ITEM_SERVICE);
163 return add_service;
164 }
165 if (service_id.equals(DISPLAY_ITEMS_SERVICE))
166 {
167
168 Element disp_service = doc.createElement(GSXML.SERVICE_ELEM);
169 disp_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
170 disp_service.setAttribute(GSXML.NAME_ATT, DISPLAY_ITEMS_SERVICE);
171 return disp_service;
172 }
173
174 if (service_id.equals(ITEM_NUM_SERVICE))
175 {
176
177 Element num_service = doc.createElement(GSXML.SERVICE_ELEM);
178 num_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
179 num_service.setAttribute(GSXML.NAME_ATT, ITEM_NUM_SERVICE);
180 return num_service;
181 }
182
183 if (service_id.equals(DELETE_ITEMS_SERVICE))
184 {
185
186 Element del_service = doc.createElement(GSXML.SERVICE_ELEM);
187 del_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
188 del_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEMS_SERVICE);
189 return del_service;
190 }
191
192 if (service_id.equals(DELETE_ITEM_SERVICE))
193 {
194
195 Element delone_service = doc.createElement(GSXML.SERVICE_ELEM);
196 delone_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
197 delone_service.setAttribute(GSXML.NAME_ATT, DELETE_ITEM_SERVICE);
198 return delone_service;
199 }
200
201 if (service_id.equals(SEND_MAIL_SERVICE))
202 {
203
204 Element mail_service = doc.createElement(GSXML.SERVICE_ELEM);
205 mail_service.setAttribute(GSXML.TYPE_ATT, "gather"); // what??
206 mail_service.setAttribute(GSXML.NAME_ATT, SEND_MAIL_SERVICE);
207 return mail_service;
208 }
209
210 return null;
211 }
212
213 protected Element processAddItem(Element request)
214 {
215 Hashtable<String, Hashtable<String, Item>> docsMap = updateDocMap(request);
216
217 // Create a new (empty) result message
218 Document result_doc = XMLConverter.newDOM();
219 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
220
221 // Get the parameters of the request
222 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
223 if (param_list == null)
224 {
225 logger.error("BerryBasket Error: AddItem request had no paramList.");
226 return result; // Return the empty result
227 }
228
229 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
230
231 String item = (String) params.get("item");
232 String collection = "";
233 int pos = item.indexOf(":");
234 if (pos != -1)
235 {
236 collection = item.substring(0, pos);
237 item = item.substring(pos + 1);
238 }
239
240 if (docsMap.containsKey(collection))
241 {
242 Hashtable<String, Item> items = docsMap.get(collection);
243 if (!items.containsKey(item))
244 {
245 Item newItem = generateItem(collection, item);
246 items.put(item, newItem);
247 result.appendChild(newItem.wrapIntoElement(result_doc));
248 }
249 }
250 else
251 {
252 Hashtable<String, Item> items = new Hashtable<String, Item>();
253 Item newItem = generateItem(collection, item);
254 items.put(item, newItem);
255 docsMap.put(collection, items);
256 result.appendChild(newItem.wrapIntoElement(result_doc));
257 }
258
259 return result;
260 }
261
262 private Item generateItem(String collection, String id)
263 {
264
265 Item item = new Item(collection, id);
266 String to = GSPath.appendLink(collection, "DocumentMetadataRetrieve");
267 ArrayList<String> tmp = new ArrayList<String>();
268 tmp.add(id);
269
270 UserContext userContext = new UserContext();
271 userContext.setLanguage("en");
272 userContext.setUserID("dumy");
273 Element response = getDocumentMetadata(to, userContext, tmp.iterator());
274 Element doc_node = (Element) response.getElementsByTagName(GSXML.DOC_NODE_ELEM).item(0);
275
276 String node_id = doc_node.getAttribute(GSXML.NODE_ID_ATT);
277 Element metadata_list = (Element) doc_node.getElementsByTagName(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER).item(0);
278
279 //assign title metadata if any
280 Element metadata = GSXML.getNamedElement(metadata_list, "metadata", "name", "Title");
281 if (metadata != null)
282 {
283 item.title = GSXML.getNodeText(metadata).trim();
284 }
285 //assign date metadata if any
286 metadata = GSXML.getNamedElement(metadata_list, "metadata", "name", "Date");
287 if (metadata != null)
288 {
289 item.date = GSXML.getNodeText(metadata).trim();
290 }
291
292 //assign root title metadata if any
293 metadata = GSXML.getNamedElement(metadata_list, "metadata", "name", "root_Title");
294 if (metadata != null)
295 {
296 String rootTitle = GSXML.getNodeText(metadata).trim();
297 if (!rootTitle.equals(item.title) && !rootTitle.equals(""))
298 {
299 item.rootTitle = rootTitle;
300 }
301
302 }
303
304 return item;
305 }
306
307 protected Element processDeleteItems(Element request)
308 {
309 Hashtable<String, Hashtable<String, Item>> docsMap = updateDocMap(request);
310
311 // Create a new (empty) result message
312 Document result_doc = XMLConverter.newDOM();
313 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
314
315 // Get the parameters of the request
316 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
317
318 if (param_list == null)
319 {
320 logger.error("BerryBasket Error: DeleteItem request had no paramList.");
321 return result; // Return the empty result
322 }
323
324 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
325
326 String param = (String) params.get("items");
327
328 if (param == null)
329 return result;
330
331 String[] items = param.split("\\|");
332
333 for (int i = 0; i < items.length; i++)
334 {
335 String item = items[i];
336 if (item.trim().length() == 0)
337 continue;
338 String collection = "";
339 int pos = item.indexOf(":");
340 if (pos != -1)
341 {
342 collection = item.substring(0, pos);
343 item = item.substring(pos + 1);
344 }
345
346 if (docsMap.containsKey(collection))
347 {
348 Hashtable itemMap = docsMap.get(collection);
349 if (itemMap.containsKey(item))
350 {
351 itemMap.remove(item);
352 }
353 if (itemMap.size() == 0)
354 {
355 docsMap.remove(collection);
356 }
357 }
358
359 }
360
361 return result;
362 }
363
364 protected Element processDeleteItem(Element request)
365 {
366 Hashtable<String, Hashtable<String, Item>> docsMap = updateDocMap(request);
367
368 // Create a new (empty) result message
369 Document result_doc = XMLConverter.newDOM();
370 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
371
372 // Get the parameters of the request
373 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
374
375 if (param_list == null)
376 {
377 logger.error("BerryBasket Error: DeleteItem request had no paramList.");
378 return result; // Return the empty result
379 }
380
381 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
382
383 String param = (String) params.get("item");
384
385 if (param == null)
386 return result;
387
388 String item = param;
389
390 String collection = "";
391 int pos = item.indexOf(":");
392
393 if (pos != -1)
394 {
395 collection = item.substring(0, pos);
396 item = item.substring(pos + 1);
397 }
398
399 if (docsMap.containsKey(collection))
400 {
401 Hashtable itemMap = docsMap.get(collection);
402 if (itemMap.containsKey(item))
403 {
404 itemMap.remove(item);
405 }
406 if (itemMap.size() == 0)
407 {
408 docsMap.remove(collection);
409 }
410 }
411
412 return result;
413 }
414
415 protected Element processItemNum(Element request)
416 {
417 Hashtable<String, Hashtable<String, Item>> docsMap = updateDocMap(request);
418
419 // Create a new (empty) result message
420 Document result_doc = XMLConverter.newDOM();
421 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
422
423 int size = 0;
424 String ids = "";
425 Iterator<String> keys = docsMap.keySet().iterator();
426
427 while (keys.hasNext())
428 {
429 Hashtable items = docsMap.get(keys.next());
430 size += items.size();
431 Iterator values = items.values().iterator();
432 while (values.hasNext())
433 {
434 Item item = (Item) values.next();
435 result.appendChild(item.wrapIntoElement(result_doc));
436 }
437 }
438
439 Element selement = result_doc.createElement("size");
440 selement.setAttribute("value", size + "");
441 result.appendChild(selement);
442
443 return result;
444 }
445
446 private Element getDocumentMetadata(String to, UserContext userContext, Iterator<String> ids)
447 {
448
449 // Build a request to obtain some document metadata
450 Document doc = XMLConverter.newDOM();
451 Element dm_message = doc.createElement(GSXML.MESSAGE_ELEM);
452 Element dm_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
453 dm_message.appendChild(dm_request);
454
455 // Create a parameter list to specify the required metadata information
456 HashSet<String> meta_names = new HashSet<String>();
457 meta_names.add("Title"); // the default
458 meta_names.add("root_Title");
459 meta_names.add("Date");
460
461 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
462
463 Element param = null;
464 Iterator<String> i = meta_names.iterator();
465 while (i.hasNext())
466 {
467 String name = i.next();
468 param = doc.createElement(GSXML.PARAM_ELEM);
469 param_list.appendChild(param);
470 param.setAttribute(GSXML.NAME_ATT, "metadata");
471 param.setAttribute(GSXML.VALUE_ATT, name);
472
473 }
474
475 dm_request.appendChild(param_list);
476
477 // create the doc node list for the metadata request
478 Element dm_doc_list = doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
479 dm_request.appendChild(dm_doc_list);
480
481 while (ids.hasNext())
482 {
483 // Add the documentNode to the list
484 Element dm_doc_node = doc.createElement(GSXML.DOC_NODE_ELEM);
485 dm_doc_list.appendChild(dm_doc_node);
486 dm_doc_node.setAttribute(GSXML.NODE_ID_ATT, ids.next());
487 }
488
489 return (Element) this.router.process(dm_message);
490
491 }
492
493 protected Element processDisplayList(Element request)
494 {
495 Hashtable<String, Hashtable<String, Item>> docsMap = updateDocMap(request);
496
497 // Create a new (empty) result message
498 Document result_doc = XMLConverter.newDOM();
499 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
500
501 Iterator<String> keys = docsMap.keySet().iterator();
502
503 while (keys.hasNext())
504 {
505 String collection = keys.next();
506 Hashtable items = docsMap.get(collection);
507 Iterator itemItr = items.values().iterator();
508
509 Element collectionNode = result_doc.createElement("berryList");
510 collectionNode.setAttribute("name", collection);
511 result.appendChild(collectionNode);
512
513 while (itemItr.hasNext())
514 {
515 Item item = (Item) itemItr.next();
516 Element itemElement = result_doc.createElement("item");
517
518 collectionNode.appendChild(itemElement);
519 itemElement.setAttribute("name", item.docid);
520 itemElement.setAttribute("collection", item.collection);
521 itemElement.setAttribute("title", item.title);
522 itemElement.setAttribute("date", item.date);
523 itemElement.setAttribute("root_title", item.rootTitle);
524 }
525 }
526
527 return result;
528
529 }
530
531 public Element processSendMail(Element request)
532 {
533 // Create a new (empty) result message
534 Document result_doc = XMLConverter.newDOM();
535 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
536
537 // Get the parameters of the request
538 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
539
540 if (param_list == null)
541 {
542 logger.error("BerryBasket Error: SendMail request had no paramList.");
543 return result; // Return the empty result
544 }
545
546 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
547
548 String to = (String) params.get("address");
549 String subject = (String) params.get("subject");
550 String content = (String) params.get("content");
551 String cc = (String) params.get("cc");
552 String bcc = (String) params.get("bcc");
553
554 String mailhost = GlobalProperties.getProperty("mail.smtp.host");
555 username = GlobalProperties.getProperty("mail.smtp.username");
556 password = GlobalProperties.getProperty("mail.smtp.password");
557 String from = GlobalProperties.getProperty("mail.from");
558 String port = GlobalProperties.getProperty("mail.smtp.port");
559 String mail_security = GlobalProperties.getProperty("mail.security");
560 String mailer = "msgsend";
561
562 try
563 {
564
565 Properties props = System.getProperties();
566
567 //Setup smtp host and from address
568 // XXX - could use Session.getTransport() and Transport.connect()
569 // XXX - assume we're using SMTP
570 if (mailhost != null && !mailhost.trim().equals(""))
571 {
572 props.put("mail.smtp.host", mailhost);
573 }
574 else
575 {
576 props.put("mail.smtp.host", "localhost");
577 }
578 if (from != null && !from.trim().equals(""))
579 {
580 props.put("mail.from", from);
581 }
582
583
584 if (port != null && !port.trim().equals("")) {
585 props.put("mail.smtp.port", port);
586 }
587
588 if (mail_security != null) {
589 mail_security = mail_security.trim();
590 if (mail_security.equals("ssl")) {
591 props.put("mail.smtp.ssl.enable", "true");
592 } else if (mail_security.equals("tls")) {
593 props.put("mail.smtp.starttls.enable", "true");
594 }
595 else if (mail_security.equals("")) {
596 logger.error("unknown security protocol "+mail_security +", should be ssl or tls");
597 }
598 }
599
600 // this doesn't seem to matter having this when
601 // username and password are empty
602 props.put("mail.smtp.auth", "true");
603
604 //setup username and password to the smtp server
605
606 if (username == null || username.trim().equals(""))
607 username = "";
608 if (password == null || password.trim().equals(""))
609 password = "";
610
611 Authenticator auth = new Authenticator()
612 {
613 protected PasswordAuthentication getPasswordAuthentication()
614 {
615 return new PasswordAuthentication(username, password);
616 }
617 };
618
619 Session session = Session.getInstance(props, auth);
620
621 Message msg = new MimeMessage(session);
622 msg.setFrom();
623 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
624 if (cc != null)
625 {
626 msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(cc, false));
627 }
628 if (bcc != null)
629 {
630 msg.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(bcc, false));
631 }
632 msg.setSubject(subject);
633 msg.setText(content.replaceAll("-------", "&"));
634 msg.setHeader("X-Mailer", mailer);
635 msg.setSentDate(new Date());
636
637 // send the thing off
638 Transport.send(msg);
639
640 logger.info("\nMail was sent successfully.");
641 result.appendChild(result_doc.createTextNode("Mail was sent successfully."));
642 }
643 catch (Exception e)
644 {
645 logger.error("Error sending mail!");
646 e.printStackTrace();
647 result.appendChild(result_doc.createTextNode(e.getMessage()));
648 }
649
650 return result;
651 }
652
653 protected class Item
654 {
655 public String collection;
656 public String docid;
657 public String title = "";
658 public String query = "";
659 public String date = "";
660 public String rootTitle = "";
661
662 public Item(String coll, String id)
663 {
664 this.collection = coll;
665 this.docid = id;
666 }
667
668 public boolean equals(Object o)
669 {
670 if (!(o instanceof Item))
671 {
672 return false;
673 }
674 Item item = (Item) o;
675 String id = collection + ":" + docid;
676 String idin = item.collection + ":" + item.docid;
677 return id.equals(idin);
678
679 }
680
681 public String toString()
682 {
683
684 return collection + ":" + docid + ":" + "[" + ((!rootTitle.equals("")) ? (rootTitle + ":") : "") + title + "]";
685 }
686
687 public Element wrapIntoElement(Document doc)
688 {
689 Element itemElement = doc.createElement("item");
690 itemElement.setAttribute("name", docid);
691 itemElement.setAttribute("collection", collection);
692 itemElement.setAttribute("title", title);
693 itemElement.setAttribute("date", date);
694 itemElement.setAttribute("root_title", rootTitle);
695 return itemElement;
696 }
697 }
698
699 private class UserTimer extends Timer implements ActionListener
700 {
701 String id = "";
702
703 public UserTimer(int delay, String id)
704 {
705 super(delay, (ActionListener) null);
706 addActionListener(this);
707 this.id = id;
708 }
709
710 public void actionPerformed(ActionEvent e)
711 {
712 userMap.remove(id);
713 timerMap.remove(id);
714 stop();
715 }
716
717 }
718
719}
Note: See TracBrowser for help on using the repository browser.