2 * This file is part of NeverNote
\r
3 * Copyright 2009 Randy Baumgarte
\r
5 * This file may be licensed under the terms of of the
\r
6 * GNU General Public License Version 2 (the ``GPL'').
\r
8 * Software distributed under the License is distributed
\r
9 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
\r
10 * express or implied. See the GPL for the specific language
\r
11 * governing rights and limitations.
\r
13 * You should have received a copy of the GPL along with this
\r
14 * program. If not, go to http://www.gnu.org/licenses/gpl.html
\r
15 * or write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
20 package cx.fbn.nevernote.threads;
\r
22 import java.io.File;
\r
23 import java.io.FileInputStream;
\r
24 import java.io.FileNotFoundException;
\r
25 import java.io.IOException;
\r
26 import java.io.InputStream;
\r
27 import java.util.List;
\r
28 import java.util.TreeSet;
\r
29 import java.util.concurrent.LinkedBlockingQueue;
\r
30 import java.util.concurrent.locks.LockSupport;
\r
32 import org.apache.commons.lang.StringEscapeUtils;
\r
33 import org.apache.tika.exception.TikaException;
\r
34 import org.apache.tika.metadata.Metadata;
\r
35 import org.apache.tika.parser.ParseContext;
\r
36 import org.apache.tika.parser.microsoft.OfficeParser;
\r
37 import org.apache.tika.parser.microsoft.ooxml.OOXMLParser;
\r
38 import org.apache.tika.parser.odf.OpenDocumentParser;
\r
39 import org.apache.tika.parser.pdf.PDFParser;
\r
40 import org.apache.tika.parser.rtf.RTFParser;
\r
41 import org.apache.tika.sax.BodyContentHandler;
\r
42 import org.xml.sax.ContentHandler;
\r
43 import org.xml.sax.SAXException;
\r
45 import com.evernote.edam.type.Data;
\r
46 import com.evernote.edam.type.Note;
\r
47 import com.evernote.edam.type.Resource;
\r
48 import com.trolltech.qt.core.QByteArray;
\r
49 import com.trolltech.qt.core.QIODevice.OpenModeFlag;
\r
50 import com.trolltech.qt.core.QObject;
\r
51 import com.trolltech.qt.core.QTemporaryFile;
\r
52 import com.trolltech.qt.xml.QDomDocument;
\r
53 import com.trolltech.qt.xml.QDomElement;
\r
54 import com.trolltech.qt.xml.QDomNodeList;
\r
56 import cx.fbn.nevernote.Global;
\r
57 import cx.fbn.nevernote.signals.IndexSignal;
\r
58 import cx.fbn.nevernote.signals.NoteResourceSignal;
\r
59 import cx.fbn.nevernote.signals.NoteSignal;
\r
60 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
61 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
63 public class IndexRunner extends QObject implements Runnable {
\r
65 private final ApplicationLogger logger;
\r
66 private String guid;
\r
67 private QByteArray resourceBinary;
\r
68 public volatile NoteSignal noteSignal;
\r
69 public volatile NoteResourceSignal resourceSignal;
\r
70 private int indexType;
\r
71 public final int SCAN=1;
\r
72 public final int REINDEXALL=2;
\r
73 public final int REINDEXNOTE=3;
\r
74 public boolean keepRunning;
\r
75 private final QDomDocument doc;
\r
76 private static String regex = Global.getWordRegex();
\r
77 public String specialIndexCharacters = "";
\r
78 public boolean indexNoteBody = true;
\r
79 public boolean indexNoteTitle = true;
\r
80 public boolean indexImageRecognition = true;
\r
81 private final DatabaseConnection conn;
\r
82 private volatile LinkedBlockingQueue<String> workQueue;
\r
83 private static int MAX_QUEUED_WAITING = 1000;
\r
84 public boolean interrupt;
\r
85 public boolean idle;
\r
86 public boolean indexAttachmentsLocally = true;
\r
87 public volatile IndexSignal signal;
\r
88 private final TreeSet<String> foundWords;
\r
89 int uncommittedCount = 0;
\r
92 public IndexRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) {
\r
93 foundWords = new TreeSet<String>();
\r
94 logger = new ApplicationLogger(logname);
\r
95 conn = new DatabaseConnection(logger, u, i, r, uid, pswd, cpswd, 500);
\r
99 doc = new QDomDocument();
\r
100 workQueue=new LinkedBlockingQueue<String>(MAX_QUEUED_WAITING);
\r
103 public void setIndexType(int t) {
\r
109 public void run() {
\r
110 thread().setPriority(Thread.MIN_PRIORITY);
\r
111 noteSignal = new NoteSignal();
\r
112 resourceSignal = new NoteResourceSignal();
\r
113 signal = new IndexSignal();
\r
114 logger.log(logger.EXTREME, "Starting index thread ");
\r
115 while (keepRunning) {
\r
118 conn.commitTransaction();
\r
119 uncommittedCount = 0;
\r
120 String work = workQueue.take();
\r
122 if (work.startsWith("SCAN")) {
\r
127 if (work.startsWith("REINDEXALL")) {
\r
129 indexType=REINDEXALL;
\r
131 if (work.startsWith("REINDEXNOTE")) {
\r
132 work = work.replace("REINDEXNOTE ", "");
\r
134 indexType = REINDEXNOTE;
\r
136 if (work.startsWith("STOP")) {
\r
137 keepRunning = false;
\r
140 logger.log(logger.EXTREME, "Type:" +indexType);
\r
141 if (indexType == SCAN && keepRunning) {
\r
142 logger.log(logger.MEDIUM, "Scanning for unindexed notes & resources");
\r
146 if (indexType == REINDEXALL && keepRunning) {
\r
147 logger.log(logger.MEDIUM, "Marking all for reindex");
\r
151 if (indexType == REINDEXNOTE && keepRunning) {
\r
154 } catch (InterruptedException e) {
\r
155 logger.log(logger.LOW, "Thread interrupted exception: " +e.getMessage());
\r
158 logger.log(logger.EXTREME, "Shutting down database");
\r
160 logger.log(logger.EXTREME, "Database shut down. Exiting thread");
\r
164 public void indexNoteContent() {
\r
165 foundWords.clear();
\r
167 logger.log(logger.EXTREME, "Entering indexRunner.indexNoteContent()");
\r
169 logger.log(logger.EXTREME, "Getting note content");
\r
170 Note n = conn.getNoteTable().getNote(guid,true,false,true,true, true);
\r
172 if (indexNoteBody) {
\r
173 data = n.getContent();
\r
174 data = conn.getNoteTable().getNoteContentNoUTFConversion(n.getGuid());
\r
176 logger.log(logger.EXTREME, "Removing any encrypted data");
\r
177 data = removeEnCrypt(data.toString());
\r
178 logger.log(logger.EXTREME, "Removing xml markups");
\r
182 if (indexNoteTitle)
\r
183 text = removeTags(StringEscapeUtils.unescapeHtml(data) +" "+ n.getTitle());
\r
185 text = removeTags(StringEscapeUtils.unescapeHtml(data));
\r
187 logger.log(logger.EXTREME, "Splitting words");
\r
188 String[] result = text.toString().split(regex);
\r
189 conn.commitTransaction();
\r
190 conn.beginTransaction();
\r
191 logger.log(logger.EXTREME, "Deleting existing words for note from index");
\r
192 conn.getWordsTable().expungeFromWordIndex(guid, "CONTENT");
\r
194 logger.log(logger.EXTREME, "Number of words found: " +result.length);
\r
195 for (int j=0; j<result.length && keepRunning; j++) {
\r
197 processInterrupt();
\r
199 if (!result[j].trim().equals("")) {
\r
200 logger.log(logger.EXTREME, "Result word: " +result[j].trim());
\r
201 addToIndex(guid, result[j], "CONTENT");
\r
204 // If we were interrupted, we will reindex this note next time
\r
205 if (Global.keepRunning) {
\r
206 logger.log(logger.EXTREME, "Resetting note guid needed");
\r
207 conn.getNoteTable().setIndexNeeded(guid, false);
\r
209 conn.commitTransaction();
\r
210 uncommittedCount = 0;
\r
211 logger.log(logger.EXTREME, "Leaving indexRunner.indexNoteContent()");
\r
215 private String removeTags(String text) {
\r
216 StringBuffer buffer = new StringBuffer(text);
\r
217 boolean inTag = false;
\r
218 for (int i=buffer.length()-1; i>=0; i--) {
\r
219 if (buffer.charAt(i) == '>')
\r
221 if (buffer.charAt(i) == '<')
\r
223 if (inTag || buffer.charAt(i) == '<')
\r
224 buffer.deleteCharAt(i);
\r
227 return buffer.toString();
\r
231 public synchronized boolean addWork(String request) {
\r
232 if (workQueue.size() == 0) {
\r
233 workQueue.offer(request);
\r
239 public synchronized int getWorkQueueSize() {
\r
240 return workQueue.size();
\r
243 public void indexResource() {
\r
247 foundWords.clear();
\r
248 Resource r = conn.getNoteTable().noteResourceTable.getNoteResourceRecognition(guid);
\r
249 if (!indexImageRecognition ||
\r
250 r == null || r.getRecognition() == null ||
\r
251 r.getRecognition().getBody() == null ||
\r
252 r.getRecognition().getBody().length == 0)
\r
253 resourceBinary = new QByteArray(" ");
\r
255 resourceBinary = new QByteArray(r.getRecognition().getBody());
\r
257 conn.commitTransaction();
\r
258 conn.beginTransaction();
\r
259 conn.getWordsTable().expungeFromWordIndex(r.getNoteGuid(), "RESOURCE");
\r
260 // This is due to an old bug & can be removed at some point in the future 11/23/2010
\r
261 conn.getWordsTable().expungeFromWordIndex(guid, "RESOURCE");
\r
262 conn.commitTransaction();
\r
263 uncommittedCount = 0;
\r
264 conn.beginTransaction();
\r
266 doc.setContent(resourceBinary);
\r
267 QDomElement docElem = doc.documentElement();
\r
269 // look for text tags
\r
270 QDomNodeList anchors = docElem.elementsByTagName("t");
\r
271 for (int i=0; i<anchors.length() && keepRunning; i++) {
\r
274 processInterrupt();
\r
277 QDomElement enmedia = anchors.at(i).toElement();
\r
278 String weight = new String(enmedia.attribute("w"));
\r
279 String text = new String(enmedia.text()).toLowerCase();
\r
280 if (!text.equals("")) {
\r
281 conn.getWordsTable().addWordToNoteIndex(r.getNoteGuid(), text, "RESOURCE", new Integer(weight));
\r
282 uncommittedCount++;
\r
283 if (uncommittedCount > 100) {
\r
284 conn.commitTransaction();
\r
285 uncommittedCount=0;
\r
290 if (Global.keepRunning && indexAttachmentsLocally) {
\r
291 conn.commitTransaction();
\r
292 uncommittedCount = 0;
\r
293 conn.beginTransaction();
\r
294 indexResourceContent(guid);
\r
297 if (Global.keepRunning)
\r
298 conn.getNoteTable().noteResourceTable.setIndexNeeded(guid,false);
\r
299 conn.commitTransaction();
\r
300 uncommittedCount = 0;
\r
303 private void indexResourceContent(String guid) {
\r
304 Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, true);
\r
305 if (r.getMime().equalsIgnoreCase("application/pdf")) {
\r
306 indexResourcePDF(r);
\r
309 if (r.getMime().equalsIgnoreCase("application/docx") ||
\r
310 r.getMime().equalsIgnoreCase("application/xlsx") ||
\r
311 r.getMime().equalsIgnoreCase("application/pptx")) {
\r
312 indexResourceOOXML(r);
\r
315 if (r.getMime().equalsIgnoreCase("application/vsd") ||
\r
316 r.getMime().equalsIgnoreCase("application/ppt") ||
\r
317 r.getMime().equalsIgnoreCase("application/xls") ||
\r
318 r.getMime().equalsIgnoreCase("application/msg") ||
\r
319 r.getMime().equalsIgnoreCase("application/doc")) {
\r
320 indexResourceOffice(r);
\r
323 if (r.getMime().equalsIgnoreCase("application/rtf")) {
\r
324 indexResourceRTF(r);
\r
327 if (r.getMime().equalsIgnoreCase("application/odf") ||
\r
328 r.getMime().equalsIgnoreCase("application/odt") ||
\r
329 r.getMime().equalsIgnoreCase("application/odp") ||
\r
330 r.getMime().equalsIgnoreCase("application/odg") ||
\r
331 r.getMime().equalsIgnoreCase("application/odb") ||
\r
332 r.getMime().equalsIgnoreCase("application/ods")) {
\r
333 indexResourceODF(r);
\r
339 private void indexResourceRTF(Resource r) {
\r
341 Data d = r.getData();
\r
342 for (int i=0; i<20 && d.getSize() == 0; i++)
\r
344 if (d.getSize()== 0)
\r
347 QTemporaryFile f = writeResource(d);
\r
348 if (!keepRunning) {
\r
354 input = new FileInputStream(new File(f.fileName()));
\r
355 ContentHandler textHandler = new BodyContentHandler(-1);
\r
356 Metadata metadata = new Metadata();
\r
357 RTFParser parser = new RTFParser();
\r
358 ParseContext context = new ParseContext();
\r
359 parser.parse(input, textHandler, metadata, context);
\r
360 String[] result = textHandler.toString().split(regex);
\r
361 for (int i=0; i<result.length && keepRunning; i++) {
\r
362 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");
\r
367 } catch (java.lang.ClassCastException e) {
\r
368 logger.log(logger.LOW, "Cast exception: " +e.getMessage());
\r
369 } catch (FileNotFoundException e) {
\r
370 logger.log(logger.LOW, "FileNotFound exception: " +e.getMessage());
\r
371 } catch (IOException e) {
\r
372 logger.log(logger.LOW, "IO exception: " +e.getMessage());
\r
373 } catch (SAXException e) {
\r
374 logger.log(logger.LOW, "SAX exception: " +e.getMessage());
\r
375 } catch (TikaException e) {
\r
376 logger.log(logger.LOW, "Tika exception: " +e.getMessage());
\r
377 } catch (Exception e) {
\r
378 logger.log(logger.LOW, "Unknown exception: " +e.getMessage());
\r
379 } catch (java.lang.NoSuchMethodError e) {
\r
380 logger.log(logger.LOW, "NoSuchMethod error: " +e.getMessage());
\r
381 } catch (Error e) {
\r
382 logger.log(logger.LOW, "Unknown error: " +e.getMessage());
\r
387 private void indexResourceODF(Resource r) {
\r
389 Data d = r.getData();
\r
390 for (int i=0; i<20 && d.getSize() == 0; i++)
\r
392 if (d.getSize()== 0)
\r
394 QTemporaryFile f = writeResource(d);
\r
395 if (!keepRunning) {
\r
401 input = new FileInputStream(new File(f.fileName()));
\r
402 ContentHandler textHandler = new BodyContentHandler(-1);
\r
403 Metadata metadata = new Metadata();
\r
404 OpenDocumentParser parser = new OpenDocumentParser();
\r
405 ParseContext context = new ParseContext();
\r
406 parser.parse(input, textHandler, metadata, context);
\r
407 String[] result = textHandler.toString().split(regex);
\r
408 for (int i=0; i<result.length && keepRunning; i++) {
\r
410 processInterrupt();
\r
412 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");
\r
417 } catch (java.lang.ClassCastException e) {
\r
418 logger.log(logger.LOW, "Cast exception: " +e.getMessage());
\r
419 } catch (FileNotFoundException e) {
\r
420 logger.log(logger.LOW, "FileNotFound exception: " +e.getMessage());
\r
421 } catch (IOException e) {
\r
422 logger.log(logger.LOW, "IO exception: " +e.getMessage());
\r
423 } catch (SAXException e) {
\r
424 logger.log(logger.LOW, "SAX exception: " +e.getMessage());
\r
425 } catch (TikaException e) {
\r
426 logger.log(logger.LOW, "Tika exception: " +e.getMessage());
\r
427 } catch (Exception e) {
\r
428 logger.log(logger.LOW, "Unknown exception: " +e.getMessage());
\r
429 } catch (java.lang.NoSuchMethodError e) {
\r
430 logger.log(logger.LOW, "NoSuchMethod error: " +e.getMessage());
\r
431 } catch (Error e) {
\r
432 logger.log(logger.LOW, "Unknown error: " +e.getMessage());
\r
437 private void indexResourceOffice(Resource r) {
\r
439 Data d = r.getData();
\r
440 for (int i=0; i<20 && d.getSize() == 0; i++)
\r
442 if (d.getSize()== 0)
\r
444 QTemporaryFile f = writeResource(d);
\r
445 if (!keepRunning) {
\r
451 input = new FileInputStream(new File(f.fileName()));
\r
452 ContentHandler textHandler = new BodyContentHandler(-1);
\r
453 Metadata metadata = new Metadata();
\r
454 OfficeParser parser = new OfficeParser();
\r
455 ParseContext context = new ParseContext();
\r
456 parser.parse(input, textHandler, metadata, context);
\r
457 String[] result = textHandler.toString().split(regex);
\r
458 for (int i=0; i<result.length && keepRunning; i++) {
\r
460 processInterrupt();
\r
462 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");
\r
467 } catch (java.lang.ClassCastException e) {
\r
468 logger.log(logger.LOW, "Cast exception: " +e.getMessage());
\r
469 } catch (FileNotFoundException e) {
\r
470 logger.log(logger.LOW, "FileNotFound exception: " +e.getMessage());
\r
471 } catch (IOException e) {
\r
472 logger.log(logger.LOW, "IO exception: " +e.getMessage());
\r
473 } catch (SAXException e) {
\r
474 logger.log(logger.LOW, "SAX exception: " +e.getMessage());
\r
475 } catch (TikaException e) {
\r
476 logger.log(logger.LOW, "Tika exception: " +e.getMessage());
\r
477 } catch (Exception e) {
\r
478 logger.log(logger.LOW, "Unknown exception: " +e.getMessage());
\r
479 } catch (java.lang.NoSuchMethodError e) {
\r
480 logger.log(logger.LOW, "NoSuchMethod error: " +e.getMessage());
\r
481 } catch (Error e) {
\r
482 logger.log(logger.LOW, "Unknown error: " +e.getMessage());
\r
488 private void indexResourcePDF(Resource r) {
\r
490 Data d = r.getData();
\r
491 for (int i=0; i<20 && d.getSize() == 0; i++)
\r
493 if (d.getSize()== 0)
\r
495 QTemporaryFile f = writeResource(d);
\r
496 if (!keepRunning) {
\r
502 input = new FileInputStream(new File(f.fileName()));
\r
503 ContentHandler textHandler = new BodyContentHandler(-1);
\r
504 Metadata metadata = new Metadata();
\r
505 PDFParser parser = new PDFParser();
\r
506 ParseContext context = new ParseContext();
\r
507 parser.parse(input, textHandler, metadata, context);
\r
508 String[] result = textHandler.toString().split(regex);
\r
509 for (int i=0; i<result.length && keepRunning; i++) {
\r
511 processInterrupt();
\r
513 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");
\r
518 } catch (java.lang.ClassCastException e) {
\r
519 logger.log(logger.LOW, "Cast exception: " +e.getMessage());
\r
520 } catch (FileNotFoundException e) {
\r
521 logger.log(logger.LOW, "FileNotFound exception: " +e.getMessage());
\r
522 } catch (IOException e) {
\r
523 logger.log(logger.LOW, "IO exception: " +e.getMessage());
\r
524 } catch (SAXException e) {
\r
525 logger.log(logger.LOW, "SAX exception: " +e.getMessage());
\r
526 } catch (TikaException e) {
\r
527 logger.log(logger.LOW, "Tika exception: " +e.getMessage());
\r
528 } catch (Exception e) {
\r
529 logger.log(logger.LOW, "Unknown exception: " +e.getMessage());
\r
530 } catch (java.lang.NoSuchMethodError e) {
\r
531 logger.log(logger.LOW, "NoSuchMethod error: " +e.getMessage());
\r
532 } catch (Error e) {
\r
533 logger.log(logger.LOW, "Unknown error: " +e.getMessage());
\r
538 private void indexResourceOOXML(Resource r) {
\r
540 Data d = r.getData();
\r
541 for (int i=0; i<20 && d.getSize() == 0; i++)
\r
543 if (d.getSize()== 0)
\r
545 QTemporaryFile f = writeResource(d);
\r
546 if (!keepRunning) {
\r
552 input = new FileInputStream(new File(f.fileName()));
\r
553 ContentHandler textHandler = new BodyContentHandler(-1);
\r
554 Metadata metadata = new Metadata();
\r
555 OOXMLParser parser = new OOXMLParser();
\r
556 ParseContext context = new ParseContext();
\r
557 parser.parse(input, textHandler, metadata, context);
\r
558 String[] result = textHandler.toString().split(regex);
\r
559 for (int i=0; i<result.length && keepRunning; i++) {
\r
561 processInterrupt();
\r
563 addToIndex(r.getNoteGuid(), result[i], "RESOURCE");
\r
568 } catch (java.lang.ClassCastException e) {
\r
569 logger.log(logger.LOW, "Cast exception: " +e.getMessage());
\r
570 } catch (FileNotFoundException e) {
\r
571 logger.log(logger.LOW, "FileNotFound exception: " +e.getMessage());
\r
572 } catch (IOException e) {
\r
573 logger.log(logger.LOW, "IO exception: " +e.getMessage());
\r
574 } catch (SAXException e) {
\r
575 logger.log(logger.LOW, "SAX exception: " +e.getMessage());
\r
576 } catch (TikaException e) {
\r
577 logger.log(logger.LOW, "Tika exception: " +e.getMessage());
\r
578 } catch (Exception e) {
\r
579 logger.log(logger.LOW, "Unknown exception: " +e.getMessage());
\r
580 } catch (java.lang.NoSuchMethodError e) {
\r
581 logger.log(logger.LOW, "NoSuchMethod error: " +e.getMessage());
\r
582 } catch (Error e) {
\r
583 logger.log(logger.LOW, "Unknown error: " +e.getMessage()); }
\r
588 private QTemporaryFile writeResource(Data d) {
\r
589 QTemporaryFile newFile = new QTemporaryFile();
\r
590 newFile.open(OpenModeFlag.WriteOnly);
\r
591 newFile.write(d.getBody());
\r
597 private String removeEnCrypt(String content) {
\r
598 int index = content.indexOf("<en-crypt");
\r
600 boolean tagFound = true;
\r
601 while (tagFound && keepRunning) {
\r
603 processInterrupt();
\r
605 endPos = content.indexOf("</en-crypt>", index)+11;
\r
606 if (endPos > -1 && index > -1) {
\r
607 content = content.substring(0,index)+content.substring(endPos);
\r
608 index = content.indexOf("<en-crypt");
\r
617 private void addToIndex(String guid, String word, String type) {
\r
618 if (foundWords.contains(word))
\r
620 StringBuffer buffer = new StringBuffer(word.toLowerCase());
\r
621 for (int i=buffer.length()-1; i>=0; i--) {
\r
622 if (!Character.isLetterOrDigit(buffer.charAt(i)) && specialIndexCharacters.indexOf(buffer.charAt(i)) == -1)
\r
623 buffer.deleteCharAt(i);
\r
627 buffer = buffer.reverse();
\r
628 for (int i=buffer.length()-1; i>=0; i--) {
\r
629 if (!Character.isLetterOrDigit(buffer.charAt(i)))
\r
630 buffer.deleteCharAt(i);
\r
634 buffer = buffer.reverse();
\r
635 if (buffer.length() > 0) {
\r
636 // We have a good word, now let's trim off junk at the beginning or end
\r
637 if (!foundWords.contains(buffer.toString())) {
\r
638 foundWords.add(buffer.toString());
\r
639 foundWords.add(word);
\r
640 conn.getWordsTable().addWordToNoteIndex(guid, buffer.toString(), type, 100);
\r
641 uncommittedCount++;
\r
642 if (uncommittedCount > 100) {
\r
643 conn.commitTransaction();
\r
644 uncommittedCount=0;
\r
651 private void scanUnindexed() {
\r
652 List<String> notes = conn.getNoteTable().getUnindexed();
\r
654 boolean started = false;
\r
655 if (notes.size() > 0) {
\r
656 signal.indexStarted.emit();
\r
659 for (int i=0; i<notes.size() && keepRunning; i++) {
\r
661 processInterrupt();
\r
663 guid = notes.get(i);
\r
664 if (guid != null && keepRunning) {
\r
665 indexNoteContent();
\r
669 List<String> unindexedResources = conn.getNoteTable().noteResourceTable.getUnindexed();
\r
670 if (unindexedResources.size() > 0 && !started) {
\r
671 signal.indexStarted.emit();
\r
674 for (int i=0; i<unindexedResources.size()&& keepRunning; i++) {
\r
676 processInterrupt();
\r
678 guid = unindexedResources.get(i);
\r
683 if (started && keepRunning)
\r
684 signal.indexFinished.emit();
\r
687 private void reindexNote() {
\r
690 conn.getNoteTable().setIndexNeeded(guid, true);
\r
693 private void reindexAll() {
\r
694 conn.getNoteTable().reindexAllNotes();
\r
695 conn.getNoteTable().noteResourceTable.reindexAll();
\r
698 private void waitSeconds(int len) {
\r
699 long starttime = 0; // variable declared
\r
701 // for the first time, remember the timestamp
\r
702 starttime = System.currentTimeMillis();
\r
703 // the next timestamp we want to wake up
\r
704 starttime += (1000.0);
\r
705 // Wait until the desired next time arrives using nanosecond
\r
706 // accuracy timer (wait(time) isn't accurate enough on most platforms)
\r
707 LockSupport.parkNanos((Math.max(0,
\r
708 starttime - System.currentTimeMillis()) * 1000000));
\r
711 private void processInterrupt() {
\r
712 conn.commitTransaction();
\r
714 uncommittedCount = 0;
\r
715 conn.beginTransaction();
\r