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 }