1 package org.paneris.bibliomania.metasearch; 2 3 import java.util.Enumeration; 4 import java.util.NoSuchElementException; 5 import java.util.Vector; 6 7 import org.melati.poem.transaction.ToTidyList; 8 import org.paneris.bibliomania.BookStocking; 9 import org.paneris.bibliomania.Bookshop; 10 11 public class Metasearch implements ToTidyList.Closeable { 12 13 private Bookshop[] shops; 14 private String title; 15 private String author; 16 private ToTidyList toTidy; 17 private SearchThread[] threads; 18 private Vector results = new Vector(); 19 private int runningThreads = 0; 20 21 private class SearchThread extends Thread { 22 private Bookshop shop; 23 24 public SearchThread(Bookshop shop) { 25 this.shop = shop; 26 } 27 28 public void run() { 29 try { 30 Enumeration books = 31 shop.backend.booksMatching(shop, title, author, "", "", toTidy); 32 while (books.hasMoreElements()) { 33 BookStocking stocking = (BookStocking)books.nextElement(); 34 shop.backend.resolve(stocking); 35 synchronized (results) { 36 results.addElement(stocking); 37 results.notifyAll(); 38 } 39 } 40 } catch (Exception e) { 41 System.err.println("Metasearch.SearchThread: " + e); 42 } finally { 43 synchronized (results) { 44 --runningThreads; 45 results.notifyAll(); 46 if (runningThreads <= 0) { 47 synchronized (Metasearch.this) { 48 Metasearch.this.notifyAll(); 49 } 50 } 51 } 52 } 53 } 54 55 public void close() { 56 try { 57 stop(); 58 } catch (Exception e) { 59 } 60 } 61 } 62 63 private class HitsEnumeration implements Enumeration { 64 65 private int nextResultIndex = 0; 66 private Object next = null; 67 68 public boolean hasMoreElements() { 69 try { 70 synchronized (results) { 71 if (next != null) 72 return true; 73 74 while (nextResultIndex >= results.size()) { 75 if (runningThreads <= 0) 76 return false; 77 results.wait(); 78 } 79 80 next = results.elementAt(nextResultIndex++); 81 return true; 82 } 83 } catch (InterruptedException e) { 84 return false; 85 } 86 } 87 88 public Object nextElement() { 89 synchronized (results) { 90 if (hasMoreElements()) { 91 Object it = next; 92 next = null; 93 return it; 94 } else 95 throw new NoSuchElementException("No more search hits"); 96 } 97 } 98 } 99 100 public Metasearch( 101 Bookshop[] shopsP, 102 String title, 103 String author, 104 ToTidyList toTidy) { 105 this.shops = shopsP; 106 this.title = title; 107 this.author = author; 108 this.toTidy = toTidy; 109 110 threads = new SearchThread[shops.length]; 111 if (toTidy != null) 112 toTidy.add(this); 113 114 for (int s = 0; s < shops.length; ++s) { 115 (threads[s] = new SearchThread(shops[s])).start(); 116 synchronized (results) { 117 ++runningThreads; 118 } 119 } 120 } 121 122 public Enumeration currentAndFutureResults() { 123 return new HitsEnumeration(); 124 } 125 126 public Vector currentResults() { 127 return results; 128 } 129 130 public boolean running() { 131 return runningThreads > 0; 132 } 133 134 public void close() { 135 try { 136 for (int i = 0; i < threads.length; ++i) 137 try { 138 threads[i].stop(); 139 } catch (Exception e) { 140 } 141 } finally { 142 synchronized (this) { 143 runningThreads = 0; 144 notifyAll(); 145 } 146 } 147 } 148 149 protected void finalize() throws Throwable { 150 close(); 151 } 152 }