1
20 package org.crosswire.jsword.book;
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.TreeSet;
31
32 import org.crosswire.common.activate.Activator;
33 import org.crosswire.common.util.CollectionUtil;
34 import org.crosswire.common.util.PluginUtil;
35 import org.crosswire.common.util.Reporter;
36 import org.crosswire.jsword.JSOtherMsg;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40
48 public final class Books extends AbstractBookList {
49
53 private Books() {
54 super();
55 initials = new HashMap<String, Book>();
56 names = new HashMap<String, Book>();
57 drivers = new HashSet<BookDriver>();
58 books = new TreeSet();
59 }
60
61
66 public static Books installed() {
67 return instance;
68 }
69
70
73 public synchronized List<Book> getBooks() {
74 return CollectionUtil.createList(books);
75 }
76
77
80 @Override
81 public synchronized List<Book> getBooks(BookFilter filter) {
82 return CollectionUtil.createList(new BookFilterIterator(books, filter));
83 }
84
85
93 public synchronized Book getBook(String name) {
94 if (name == null) {
95 return null;
96 }
97
98 Book book = initials.get(name);
99 if (book != null) {
100 return book;
101 }
102
103 book = names.get(name);
104 if (book != null) {
105 return book;
106 }
107
108 for (Book b : books) {
110 if (name.equalsIgnoreCase(b.getInitials()) || name.equalsIgnoreCase(b.getName())) {
111 return b;
112 }
113 }
114
115 return null;
116 }
117
118
124 public synchronized void addBook(Book book) {
125 if (book != null && books.add(book)) {
126 initials.put(book.getInitials(), book);
127 names.put(book.getName(), book);
128 fireBooksChanged(instance, book, true);
129 }
130 }
131
132
139 public synchronized void removeBook(Book book) throws BookException {
140
142 Activator.deactivate(book);
143
144 boolean removed = books.remove(book);
145 if (removed) {
146 initials.remove(book.getInitials());
147 names.remove(book.getName());
148 fireBooksChanged(instance, book, false);
149 } else {
150 throw new BookException(JSOtherMsg.lookupText("Could not remove unregistered Book: {0}", book.getName()));
151 }
152 }
153
154
163 public synchronized void registerDriver(BookDriver driver) throws BookException {
164 log.debug("begin registering driver: {}", driver.getClass().getName());
165
166 drivers.add(driver);
167
168 Book[] bookArray = driver.getBooks();
171 Set<Book> current = CollectionUtil.createSet(new BookFilterIterator(books, BookFilters.getBooksByDriver(driver)));
172
173 for (int j = 0; j < bookArray.length; j++) {
174 Book b = bookArray[j];
175 if (current.contains(b)) {
176 current.remove(b);
180 } else {
181 addBook(bookArray[j]);
182 }
183 }
184
185 for (Book book : current) {
188 removeBook(book);
189 }
190
191 log.debug("end registering driver: {}", driver.getClass().getName());
192 }
193
194
202 public synchronized BookDriver[] getDriversByClass(Class<? extends BookDriver> type) {
203 List<BookDriver> matches = new ArrayList<BookDriver>();
204 for (BookDriver driver : drivers) {
205 if (driver.getClass() == type) {
206 matches.add(driver);
207 }
208 }
209
210 return matches.toArray(new BookDriver[matches.size()]);
211 }
212
213
218 public synchronized BookDriver[] getDrivers() {
219 return drivers.toArray(new BookDriver[drivers.size()]);
220 }
221
222
225 private void autoRegister() {
226 Class<? extends BookDriver>[] types = PluginUtil.getImplementors(BookDriver.class);
228
229 log.debug("begin auto-registering {} drivers:", Integer.toString(types.length));
230
231 for (int i = 0; i < types.length; i++) {
232
235 try {
236 Method driverInstance = types[i].getMethod("instance", new Class[0]);
237 BookDriver driver = (BookDriver) driverInstance.invoke(null, new Object[0]); registerDriver(driver);
239 } catch (NoSuchMethodException e) {
240 Reporter.informUser(Books.class, e);
241 } catch (IllegalArgumentException e) {
242 Reporter.informUser(Books.class, e);
243 } catch (IllegalAccessException e) {
244 Reporter.informUser(Books.class, e);
245 } catch (InvocationTargetException e) {
246 Reporter.informUser(Books.class, e);
247 } catch (BookException e) {
248 Reporter.informUser(Books.class, e);
249 }
250 }
251 }
252
253
256 private Set<Book> books;
257
258
261 private Map<String, Book> initials;
262
263
266 private Map<String, Book> names;
267
268
271 private Set<BookDriver> drivers;
272
273
276 private static final Logger log = LoggerFactory.getLogger(Books.class);
277
278
282 private static final Books instance = new Books();
283 static {
287 log.trace("Auto-registering start @ {}", Long.toString(System.currentTimeMillis()));
288 instance.autoRegister();
289 log.trace("Auto-registering stop @ {}", Long.toString(System.currentTimeMillis()));
290 }
291 }
292