/* * Copyright (C) 2010-2012 Geometer Plus <contact@geometerplus.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ package org.geometerplus.fbreader.network.tree; import java.util.*; import org.geometerplus.zlibrary.core.network.ZLNetworkException; import org.geometerplus.fbreader.network.NetworkLibrary; import org.geometerplus.fbreader.network.NetworkItem; public abstract class NetworkItemsLoader implements Runnable { private final NetworkCatalogTree myTree; private volatile Runnable myPostRunnable; private volatile boolean myFinishedFlag; protected NetworkItemsLoader(NetworkCatalogTree tree) { myTree = tree; } public final void start() { final Thread loaderThread = new Thread(this); loaderThread.setPriority(Thread.MIN_PRIORITY); loaderThread.start(); } public NetworkCatalogTree getTree() { return myTree; } public final void run() { final NetworkLibrary library = NetworkLibrary.Instance(); try { synchronized (library) { final NetworkCatalogTree tree = getTree(); if (library.isLoadingInProgress(tree)) { return; } library.storeLoader(tree, this); } library.fireModelChangedEvent(NetworkLibrary.ChangeListener.Code.SomeCode); try { doBefore(); } catch (ZLNetworkException e) { onFinish(e, false); return; } try { doLoading(); onFinish(null, isLoadingInterrupted()); } catch (ZLNetworkException e) { onFinish(e, isLoadingInterrupted()); } } finally { library.removeStoredLoader(getTree()); library.fireModelChangedEvent(NetworkLibrary.ChangeListener.Code.SomeCode); synchronized (this) { if (myPostRunnable != null) { myPostRunnable.run(); myFinishedFlag = true; } } } } private final Object myInterruptLock = new Object(); private enum InterruptionState { NONE, REQUESTED, CONFIRMED }; private InterruptionState myInterruptionState = InterruptionState.NONE; public final boolean canResumeLoading() { synchronized (myInterruptLock) { if (myInterruptionState == InterruptionState.REQUESTED) { myInterruptionState = InterruptionState.NONE; } return myInterruptionState == InterruptionState.NONE; } } protected final boolean isLoadingInterrupted() { synchronized (myInterruptLock) { return myInterruptionState == InterruptionState.CONFIRMED; } } public void interrupt() { synchronized (myInterruptLock) { if (myInterruptionState == InterruptionState.NONE) { myInterruptionState = InterruptionState.REQUESTED; } } } public final boolean confirmInterruption() { synchronized (myInterruptLock) { if (myInterruptionState == InterruptionState.REQUESTED) { myInterruptionState = InterruptionState.CONFIRMED; } return myInterruptionState == InterruptionState.CONFIRMED; } } public void onNewItem(final NetworkItem item) { getTree().addItem(item); } public synchronized void setPostRunnable(Runnable action) { if (myFinishedFlag) { action.run(); } else { myPostRunnable = action; } } protected abstract void onFinish(ZLNetworkException exception, boolean interrupted); protected abstract void doBefore() throws ZLNetworkException; protected abstract void doLoading() throws ZLNetworkException; }