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.util.GregorianCalendar;
\r
23 import java.util.List;
\r
24 import java.util.concurrent.LinkedBlockingQueue;
\r
26 import com.evernote.edam.type.Resource;
\r
27 import com.trolltech.qt.core.QMutex;
\r
28 import com.trolltech.qt.core.QObject;
\r
30 import cx.fbn.nevernote.Global;
\r
31 import cx.fbn.nevernote.evernote.EnmlConverter;
\r
32 import cx.fbn.nevernote.signals.NoteSignal;
\r
33 import cx.fbn.nevernote.sql.DatabaseConnection;
\r
34 import cx.fbn.nevernote.utilities.ApplicationLogger;
\r
35 import cx.fbn.nevernote.utilities.Pair;
\r
37 public class SaveRunner extends QObject implements Runnable {
\r
39 private final ApplicationLogger logger;
\r
40 public volatile boolean keepRunning;
\r
41 public QMutex threadLock;
\r
42 private final DatabaseConnection conn;
\r
43 private boolean idle;
\r
44 public NoteSignal noteSignals;
\r
46 private volatile LinkedBlockingQueue<Pair<String, String>> workQueue = new LinkedBlockingQueue<Pair<String, String>>();
\r
49 //*********************************************
\r
51 //*********************************************
\r
52 public SaveRunner(String logname, String u, String i, String r, String uid, String pswd, String cpswd) {
\r
53 logger = new ApplicationLogger(logname);
\r
54 conn = new DatabaseConnection(logger, u, i, r, uid, pswd, cpswd, 0);
\r
55 threadLock = new QMutex();
\r
57 noteSignals = new NoteSignal();
\r
60 public SaveRunner(ApplicationLogger l, DatabaseConnection c) {
\r
64 noteSignals = new NoteSignal();
\r
69 //*********************************************
\r
71 //*********************************************
\r
74 thread().setPriority(Thread.MIN_PRIORITY);
\r
75 boolean keepRunning = true;
\r
77 while(keepRunning) {
\r
79 Pair<String, String> content;
\r
81 content = workQueue.take();
\r
82 if (!content.getFirst().equalsIgnoreCase("stop")) {
\r
85 // This is a bit of a hack. It causes this thread to pause for 0.2 seconds.
\r
86 // This helps make sure that the main thread gets to the
\r
87 // database first when switching notes, othrewise it really
\r
88 // slows things down when fetching new notes.
\r
89 GregorianCalendar now = new GregorianCalendar();
\r
90 long prev = now.getTimeInMillis();
\r
92 while (prev>now.getTimeInMillis()) {
\r
93 now = new GregorianCalendar();
\r
96 updateNoteContent(content.getFirst(), content.getSecond());
\r
100 threadLock.unlock();
\r
101 } catch (InterruptedException e) { }
\r
107 public synchronized void addWork(String guid, String content) {
\r
108 while(workQueue.size() > 0) {}
\r
109 Pair<String, String> pair = new Pair<String, String>(guid, content);
\r
110 workQueue.offer(pair);
\r
113 public synchronized void release(String guid, String content) {
\r
114 Pair<String, String> pair = new Pair<String, String>(guid, content);
\r
115 workQueue.add(pair);
\r
118 public synchronized int getWorkQueueSize() {
\r
119 return workQueue.size();
\r
123 //*********************************************
\r
124 //* Getter & Setter method to tell the thread *
\r
125 //* to keep running. *
\r
126 //*********************************************
\r
127 public void setKeepRunning(boolean b) {
\r
130 public boolean keepRunning() {
\r
131 return keepRunning;
\r
134 public boolean isIdle() {
\r
139 //*********************************************
\r
140 //* Do the actual work *
\r
141 //*********************************************
\r
142 public void updateNoteContent(String guid, String content) {
\r
143 logger.log(logger.HIGH, "Entering ListManager.updateNoteContent");
\r
145 // Actually save the content
\r
146 EnmlConverter enml = new EnmlConverter(logger);
\r
147 String newContent = enml.convert(guid, content);
\r
148 String fixedContent = enml.fixEnXMLCrap(newContent);
\r
149 if (fixedContent != null) {
\r
150 conn.getNoteTable().updateNoteContent(guid, fixedContent);
\r
151 logger.log(logger.EXTREME, "Saving new note resources");
\r
152 List<Resource> oldResources = conn.getNoteTable().noteResourceTable.getNoteResources(guid, false);
\r
153 List<String> newResources = enml.getResources();
\r
154 removeObsoleteResources(oldResources, newResources);
\r
156 noteSignals.noteSaveRunnerError.emit(guid, null);
\r
158 logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent");
\r
161 // Remove resources that are no longer needed
\r
162 private void removeObsoleteResources(List<Resource> oldResources, List<String> newResources) {
\r
163 if (oldResources == null || oldResources.size() == 0)
\r
165 if (newResources == null || newResources.size() == 0) {
\r
166 for (int i=0; i<oldResources.size(); i++) {
\r
167 conn.getNoteTable().noteResourceTable.expungeNoteResource(oldResources.get(i).getGuid());
\r
170 for (int i=0; i<oldResources.size(); i++) {
\r
171 boolean matchFound = false;
\r
172 for (int j=0; j<newResources.size(); j++) {
\r
173 if (newResources.get(j).equalsIgnoreCase(oldResources.get(i).getGuid()))
\r
175 if (Global.resourceMap.get(newResources.get(j))!= null) {
\r
176 if (Global.resourceMap.get(newResources.get(j)).equalsIgnoreCase(oldResources.get(i).getGuid()))
\r
180 j = newResources.size();
\r
183 conn.getNoteTable().noteResourceTable.expungeNoteResource(oldResources.get(i).getGuid());
\r