| SwordGenBook.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 or later
5 * as published by the Free Software Foundation. This program is distributed
6 * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * Copyright: 2005-2013
18 * The copyright to this program is held by it's authors.
19 *
20 */
21 package org.crosswire.jsword.book.sword;
22
23 import java.io.IOException;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.crosswire.common.activate.Activator;
30 import org.crosswire.common.activate.Lock;
31 import org.crosswire.common.util.IOUtil;
32 import org.crosswire.jsword.JSMsg;
33 import org.crosswire.jsword.JSOtherMsg;
34 import org.crosswire.jsword.book.BookException;
35 import org.crosswire.jsword.book.basic.AbstractBook;
36 import org.crosswire.jsword.book.filter.Filter;
37 import org.crosswire.jsword.book.sword.processing.RawTextToXmlProcessor;
38 import org.crosswire.jsword.book.sword.state.OpenFileState;
39 import org.crosswire.jsword.passage.DefaultKeyList;
40 import org.crosswire.jsword.passage.Key;
41 import org.crosswire.jsword.passage.NoSuchKeyException;
42 import org.crosswire.jsword.passage.ReadOnlyKeyList;
43 import org.crosswire.jsword.passage.VerseRange;
44 import org.jdom2.Content;
45
46 /**
47 * A Sword version of Dictionary.
48 *
49 * @see gnu.lgpl.License for license details.<br>
50 * The copyright to this program is held by it's authors.
51 * @author Joe Walker [joe at eireneh dot com]
52 */
53 public class SwordGenBook extends AbstractBook {
54 /**
55 * Start and to as much checking as we can without using memory. (i.e.
56 * actually reading the indexes)
57 */
58 protected SwordGenBook(SwordBookMetaData sbmd, AbstractBackend backend) {
59 super(sbmd);
60
61 this.backend = backend;
62 this.filter = sbmd.getFilter();
63 map = null;
64 set = null;
65 global = null;
66 active = false;
67 }
68
69 /* (non-Javadoc)
70 * @see org.crosswire.jsword.book.basic.AbstractBook#activate(org.crosswire.common.activate.Lock)
71 */
72 @Override
73 public final void activate(Lock lock) {
74 super.activate(lock);
75
76 set = backend.readIndex();
77
78 map = new HashMap<String, Key>();
79 for (Key key : set) {
80 map.put(key.getName(), key);
81 }
82
83 global = new ReadOnlyKeyList(set, false);
84
85 active = true;
86
87 // We don't need to activate the backend because it should be capable
88 // of doing it for itself.
89 }
90
91 /* (non-Javadoc)
92 * @see org.crosswire.jsword.book.basic.AbstractBook#deactivate(org.crosswire.common.activate.Lock)
93 */
94 @Override
95 public final void deactivate(Lock lock) {
96 super.deactivate(lock);
97
98 map = null;
99 set = null;
100 global = null;
101
102 active = false;
103 }
104
105 /* (non-Javadoc)
106 * @see org.crosswire.jsword.book.Book#getOsisIterator(org.crosswire.jsword.passage.Key, boolean)
107 */
108 public Iterator<Content> getOsisIterator(Key key, boolean allowEmpty) throws BookException {
109 checkActive();
110
111 assert key != null;
112 assert backend != null;
113
114 return backend.readToOsis(key, new RawTextToXmlProcessor() {
115 public void preRange(VerseRange range, List<Content> partialDom) {
116 // no - op
117 }
118
119 public void postVerse(Key verse, List<Content> partialDom, String rawText) {
120 partialDom.addAll(filter.toOSIS(SwordGenBook.this, verse, rawText));
121 }
122
123 public void init(List<Content> partialDom) {
124 // no-op
125 }
126 }).iterator();
127 }
128
129 /* (non-Javadoc)
130 * @see org.crosswire.jsword.book.Book#getRawText(org.crosswire.jsword.passage.Key)
131 */
132 public String getRawText(Key key) throws BookException {
133 OpenFileState state = null;
134 try {
135 state = backend.initState();
136 return backend.readRawContent(state, key);
137 } catch (IOException e) {
138 throw new BookException("Unable to obtain raw content from backend", e);
139 } finally {
140 IOUtil.close(state);
141 }
142 }
143
144 /* (non-Javadoc)
145 * @see org.crosswire.jsword.book.Book#contains(org.crosswire.jsword.passage.Key)
146 */
147 public boolean contains(Key key) {
148 return backend != null && backend.contains(key);
149 }
150
151 /*
152 * (non-Javadoc)
153 * @see org.crosswire.jsword.book.basic.AbstractBook#getOsis(org.crosswire.jsword.passage.Key, org.crosswire.jsword.book.sword.processing.RawTextToXmlProcessor)
154 */
155 @Override
156 public List<Content> getOsis(Key key, RawTextToXmlProcessor processor) throws BookException {
157 checkActive();
158
159 assert key != null;
160 assert backend != null;
161
162 return backend.readToOsis(key, processor);
163 }
164
165 /* (non-Javadoc)
166 * @see org.crosswire.jsword.book.Book#isWritable()
167 */
168 public boolean isWritable() {
169 return backend.isWritable();
170 }
171
172 /* (non-Javadoc)
173 * @see org.crosswire.jsword.book.Book#setRawText(org.crosswire.jsword.passage.Key, java.lang.String)
174 */
175 public void setRawText(Key key, String rawData) throws BookException {
176 throw new BookException(JSOtherMsg.lookupText("This Book is read-only."));
177 }
178
179 /* (non-Javadoc)
180 * @see org.crosswire.jsword.book.Book#setAliasKey(org.crosswire.jsword.passage.Key, org.crosswire.jsword.passage.Key)
181 */
182 public void setAliasKey(Key alias, Key source) throws BookException {
183 throw new BookException(JSOtherMsg.lookupText("This Book is read-only."));
184 }
185
186 /* (non-Javadoc)
187 * @see org.crosswire.jsword.passage.KeyFactory#getGlobalKeyList()
188 */
189 public Key getGlobalKeyList() {
190 checkActive();
191
192 return global;
193 }
194
195 /* (non-Javadoc)
196 * @see org.crosswire.jsword.passage.KeyFactory#getValidKey(java.lang.String)
197 */
198 public Key getValidKey(String name) {
199 try {
200 return getKey(name);
201 } catch (NoSuchKeyException e) {
202 return createEmptyKeyList();
203 }
204 }
205
206 /* (non-Javadoc)
207 * @see org.crosswire.jsword.passage.KeyFactory#getKey(java.lang.String)
208 */
209 public Key getKey(String text) throws NoSuchKeyException {
210 checkActive();
211
212 Key key = map.get(text);
213 if (key != null) {
214 return key;
215 }
216
217 // First check for keys that match ignoring case
218 for (String keyName : map.keySet()) {
219 if (keyName.equalsIgnoreCase(text)) {
220 return map.get(keyName);
221 }
222 }
223
224 // Next keys that start with the given text
225 for (String keyName : map.keySet()) {
226 if (keyName.startsWith(text)) {
227 return map.get(keyName);
228 }
229 }
230
231 // Next try keys that contain the given text
232 for (String keyName : map.keySet()) {
233 if (keyName.indexOf(text) != -1) {
234 return map.get(keyName);
235 }
236 }
237
238 // TRANSLATOR: Error condition: Indicates that something could not be
239 // found in the book.
240 // {0} is a placeholder for the unknown key.
241 // {1} is the short name of the book
242 throw new NoSuchKeyException(JSMsg.gettext("No entry for '{0}' in {1}.", text, getInitials()));
243 }
244
245 /* (non-Javadoc)
246 * @see org.crosswire.jsword.passage.KeyFactory#createEmptyKeyList()
247 */
248 public Key createEmptyKeyList() {
249 return new DefaultKeyList();
250 }
251
252 /**
253 * Helper method so we can quickly activate ourselves on access
254 */
255 private void checkActive() {
256 if (!active) {
257 Activator.activate(this);
258 }
259 }
260
261 /**
262 * The global key list
263 */
264 private Key global;
265
266 /**
267 * Are we active
268 */
269 private boolean active;
270
271 /**
272 * So we can quickly find a Key given the text for the key
273 */
274 private Map<String, Key> map;
275
276 /**
277 * So we can implement getIndex() easily
278 */
279 private Key set;
280
281 /**
282 * To read the data from the disk
283 */
284 private AbstractBackend backend;
285
286 /**
287 * The filter to use to convert to OSIS.
288 */
289 protected Filter filter;
290
291 }
292