/*
* This file is part of NeighborNote
* Copyright 2013 Yuki Takahashi
*
* This file may be licensed under the terms of of the
* GNU General Public License Version 2 (the ``GPL'').
*
* Software distributed under the License is distributed
* on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
* express or implied. See the GPL for the specific language
* governing rights and limitations.
*
* You should have received a copy of the GPL along with this
* program. If not, go to http://www.gnu.org/licenses/gpl.html
* or write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
package cx.fbn.nevernote.threads;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import com.evernote.edam.error.EDAMErrorCode;
import com.evernote.edam.error.EDAMNotFoundException;
import com.evernote.edam.error.EDAMSystemException;
import com.evernote.edam.error.EDAMUserException;
import com.evernote.edam.notestore.RelatedQuery;
import com.evernote.edam.notestore.RelatedResult;
import com.evernote.edam.notestore.RelatedResultSpec;
import com.evernote.edam.type.Note;
import com.evernote.thrift.TException;
import com.trolltech.qt.core.QMutex;
import com.trolltech.qt.core.QObject;
import cx.fbn.nevernote.Global;
import cx.fbn.nevernote.signals.ENRelatedNotesSignal;
import cx.fbn.nevernote.signals.LimitSignal;
import cx.fbn.nevernote.utilities.ApplicationLogger;
import cx.fbn.nevernote.utilities.Pair;
public class ENRelatedNotesRunner extends QObject implements Runnable{
private final ApplicationLogger logger;
private final SyncRunner syncRunner;
public volatile ENRelatedNotesSignal enRelatedNotesSignal;
public QMutex mutex;
private volatile boolean keepRunning;
private volatile LinkedBlockingQueue<String> workQueue;
private volatile LinkedBlockingQueue<Pair<String, List<String>>> resultQueue; // ペア<元ノートguid, 関連ノートguidリスト>を溜めておくキュー
public volatile LimitSignal limitSignal;
public ENRelatedNotesRunner(SyncRunner syncRunner, String logname) {
this.logger = new ApplicationLogger(logname);
this.syncRunner = syncRunner;
this.enRelatedNotesSignal = new ENRelatedNotesSignal();
this.mutex = new QMutex();
this.keepRunning = true;
this.workQueue = new LinkedBlockingQueue<String>();
this.resultQueue = new LinkedBlockingQueue<Pair<String, List<String>>>();
this.limitSignal = new LimitSignal();
}
@Override
public void run() {
thread().setPriority(Thread.MIN_PRIORITY);
logger.log(logger.MEDIUM, "ENRelatedNotesスレッド開始");
while (keepRunning) {
try {
String work = workQueue.take();
mutex.lock();
if (work.startsWith("GET")) {
String guid = work.replace("GET ", "");
logger.log(logger.EXTREME, "Evernote関連ノート取得開始 guid = " + guid);
List<Note> relatedNotes = getENRelatedNotes(guid);
Pair<String, List<String>> resultPair = new Pair<String, List<String>>();
resultPair.setFirst(guid);
if (relatedNotes == null) { // 取得に失敗
logger.log(logger.EXTREME, "Evernote関連ノートの取得に失敗");
} else if (relatedNotes.isEmpty()) { // このノートにEvernote関連ノートは存在しない
logger.log(logger.EXTREME, "Evernote関連ノートの取得に成功 関連ノートは存在しなかった");
resultPair.setSecond(new ArrayList<String>());
} else { // Evernote関連ノートが存在する
logger.log(logger.EXTREME, "Evernote関連ノートの取得に成功 関連ノートは存在した");
List<String> relatedNoteGuids = new ArrayList<String>();
for (Note relatedNote : relatedNotes) {
relatedNoteGuids.add(relatedNote.getGuid());
}
resultPair.setSecond(relatedNoteGuids);
}
resultQueue.offer(resultPair);
enRelatedNotesSignal.getENRelatedNotesFinished.emit();
logger.log(logger.EXTREME, "Evernote関連ノート取得完了 guid = " + guid);
} else if (work.startsWith("STOP")) {
logger.log(logger.MEDIUM, "ENRelatedNotesスレッド停止");
keepRunning = false;
}
mutex.unlock();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
}
}
private List<Note> getENRelatedNotes(String guid) {
RelatedResult result = getENRelatedResult(guid);
List<Note> relatedNotes = new ArrayList<Note>();
if (result != null) {
relatedNotes = result.getNotes();
return relatedNotes;
}
return null;
}
private RelatedResult getENRelatedResult(String guid) {
if (!Global.isConnected) {
return null;
}
RelatedQuery rquery = new RelatedQuery();
rquery.setNoteGuid(guid);
RelatedResultSpec resultSpec = new RelatedResultSpec();
resultSpec.setMaxNotes(5);
if (syncRunner != null && syncRunner.localNoteStore != null) {
try {
RelatedResult result = syncRunner.localNoteStore.findRelated(syncRunner.authToken, rquery, resultSpec);
return result;
} catch (EDAMUserException e) {
logger.log(logger.HIGH, "Evernote関連ノート取得中に例外発生:EDAMUserException");
} catch (EDAMSystemException e) {
if (e.getErrorCode() == EDAMErrorCode.RATE_LIMIT_REACHED) {
limitSignal.rateLimitReached.emit(e.getRateLimitDuration());
}
logger.log(logger.HIGH, "Evernote関連ノート取得中に例外発生:EDAMSystemException");
} catch (EDAMNotFoundException e) {
logger.log(logger.HIGH, "Evernote関連ノート取得中に例外発生:EDAMnotFoundException guid = " + guid);
} catch (TException e) {
logger.log(logger.HIGH, "Evernote関連ノート取得中に例外発生:TException");
}
}
return null;
}
public boolean isKeepRunning() {
return keepRunning;
}
public void setKeepRunning(boolean keepRunning) {
this.keepRunning = keepRunning;
}
public boolean addGuid(String guid) {
if (workQueue.offer("GET " + guid)) {
return true;
}
return false;
}
public boolean addStop() {
if (workQueue.offer("STOP")) {
return true;
}
return false;
}
public synchronized Pair<String, List<String>> getENRelatedNoteGuids() {
try {
return resultQueue.take();
} catch (InterruptedException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
return null;
}
}