OSDN Git Service

a93fd17993914caf91c3bfc5e76d2b416556ef65
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / threads / SaveRunner.java
1 /*\r
2  * This file is part of NeverNote \r
3  * Copyright 2009 Randy Baumgarte\r
4  * \r
5  * This file may be licensed under the terms of of the\r
6  * GNU General Public License Version 2 (the ``GPL'').\r
7  *\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
12  *\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
17  *\r
18 */\r
19 \r
20 package cx.fbn.nevernote.threads;\r
21 \r
22 import java.util.GregorianCalendar;\r
23 import java.util.List;\r
24 import java.util.concurrent.LinkedBlockingQueue;\r
25 \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
29 \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
36 \r
37 public class SaveRunner extends QObject implements Runnable {\r
38          \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
45 \r
46         private volatile LinkedBlockingQueue<Pair<String, String>> workQueue = new LinkedBlockingQueue<Pair<String, String>>();\r
47         \r
48         \r
49         //*********************************************\r
50         //* Constructor                               *\r
51         //*********************************************\r
52         public SaveRunner(String logname, String u, String uid, String pswd, String cpswd) {\r
53                 logger = new ApplicationLogger(logname);\r
54                 conn = new DatabaseConnection(logger, u, uid, pswd, cpswd, 0);\r
55                 threadLock = new QMutex();\r
56                 keepRunning = true;\r
57                 noteSignals = new NoteSignal();\r
58         }\r
59         \r
60         \r
61         \r
62         //*********************************************\r
63         //* Run unit                                  *\r
64         //*********************************************\r
65         @Override\r
66         public void run() {\r
67                 thread().setPriority(Thread.MIN_PRIORITY);\r
68                 boolean keepRunning = true;\r
69                 \r
70                 while(keepRunning) {\r
71                         try {\r
72                                 Pair<String, String> content;\r
73                                 idle = true;\r
74                                 content = workQueue.take();\r
75                                 if (!content.getFirst().equalsIgnoreCase("stop")) {                                             \r
76                                         idle = false;\r
77                                         \r
78                                         // This is a bit of a hack.  It causes this thread to pause for 0.2 seconds.\r
79                                         // This helps make sure that the main thread gets to the\r
80                                         // database first when switching notes, othrewise it really \r
81                                         // slows things down when fetching new notes.\r
82                                         GregorianCalendar now = new GregorianCalendar();\r
83                                         long prev = now.getTimeInMillis();\r
84                                         prev = prev+200;\r
85                                         while (prev>now.getTimeInMillis()) {\r
86                                                 now = new GregorianCalendar();                                          \r
87                                         }\r
88                                         \r
89                                         updateNoteContent(content.getFirst(), content.getSecond());\r
90                                 } else {\r
91                                         return;\r
92                                 }\r
93                                 threadLock.unlock();\r
94                         } catch (InterruptedException e) { }\r
95                 }\r
96                 conn.dbShutdown();\r
97         }\r
98         \r
99         \r
100         public synchronized void addWork(String guid, String content) {\r
101                 while(workQueue.size() > 0) {}\r
102                 Pair<String, String> pair = new Pair<String, String>(guid, content);\r
103                 workQueue.offer(pair);\r
104         }\r
105         \r
106         public synchronized void release(String guid, String content) {\r
107                 Pair<String, String> pair = new Pair<String, String>(guid, content);\r
108                 workQueue.add(pair);\r
109         }\r
110         \r
111         public synchronized int getWorkQueueSize() {\r
112                 return workQueue.size();\r
113         }\r
114 \r
115         \r
116         //*********************************************\r
117         //* Getter & Setter method to tell the thread *\r
118         //* to keep running.                          *\r
119         //*********************************************\r
120         public void setKeepRunning(boolean b) {\r
121                 keepRunning = b;\r
122         }\r
123         public boolean keepRunning() {\r
124                 return keepRunning;\r
125         }\r
126         \r
127         public boolean isIdle() {\r
128                 return idle;\r
129         }\r
130         \r
131         \r
132         //*********************************************\r
133         //* Do the actual work                                *\r
134         //*********************************************\r
135         public void updateNoteContent(String guid, String content) {\r
136                 logger.log(logger.HIGH, "Entering ListManager.updateNoteContent");\r
137                 \r
138                 // Actually save the content\r
139                 EnmlConverter enml = new EnmlConverter(logger);\r
140                 String newContent = enml.convert(guid, content);\r
141                 String fixedContent = enml.fixEnXMLCrap(newContent);\r
142                 if (fixedContent != null) {\r
143                         conn.getNoteTable().updateNoteContent(guid, fixedContent);\r
144                         logger.log(logger.EXTREME, "Saving new note resources");\r
145                         List<Resource> oldResources = conn.getNoteTable().noteResourceTable.getNoteResources(guid, false);\r
146                         List<String> newResources = enml.getResources();\r
147                         removeObsoleteResources(oldResources, newResources);\r
148                 } else {\r
149                         noteSignals.noteSaveRunnerError.emit(guid, null);\r
150                 }\r
151                 logger.log(logger.HIGH, "Leaving ListManager.updateNoteContent");\r
152         }\r
153         \r
154         // Remove resources that are no longer needed\r
155         private void removeObsoleteResources(List<Resource> oldResources, List<String> newResources) {\r
156                 if (oldResources == null || oldResources.size() == 0)\r
157                         return;\r
158                 if (newResources == null || newResources.size() == 0) {\r
159                         for (int i=0; i<oldResources.size(); i++) {\r
160                                 conn.getNoteTable().noteResourceTable.expungeNoteResource(oldResources.get(i).getGuid());\r
161                         }\r
162                 }\r
163                 for (int i=0; i<oldResources.size(); i++) {\r
164                         boolean matchFound = false;\r
165                         for (int j=0; j<newResources.size(); j++) {\r
166                                 if (newResources.get(j).equalsIgnoreCase(oldResources.get(i).getGuid())) \r
167                                         matchFound = true;\r
168                                 if (Global.resourceMap.get(newResources.get(j))!= null) {\r
169                                         if (Global.resourceMap.get(newResources.get(j)).equalsIgnoreCase(oldResources.get(i).getGuid())) \r
170                                                 matchFound = true;\r
171                                 }\r
172                                 if (matchFound)\r
173                                         j = newResources.size();\r
174                         }\r
175                         if (!matchFound)\r
176                                 conn.getNoteTable().noteResourceTable.expungeNoteResource(oldResources.get(i).getGuid());\r
177                 }\r
178         }\r
179 }\r