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

Last change on this file since 32308 was 32308, checked in by kjdon, 6 years ago

make metadata dynamic in a hashmap instead of named fields in am Item - much easier to add an extra metadata field. specify it in a metadataList in berryBasket servicerack element, and it will automatically appear in berry basket results.

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