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

Last change on this file since 33084 was 33084, checked in by kjdon, 5 years ago

uid is no longer an attribute of the request. Instead its part of the UserContext. Improvement - if there is a username (=someone has logged in) then use the username as the berry basket key, that way if someone logs in they can see their basket across computers. if no username, use the id as before

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