001: /*
002: * GNetWatch
003: * Copyright 2006, 2007 Alexandre Fenyo
004: * gnetwatch@fenyo.net
005: *
006: * This file is part of GNetWatch.
007: *
008: * GNetWatch is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License as published by
010: * the Free Software Foundation; either version 2 of the License, or
011: * (at your option) any later version.
012: *
013: * GNetWatch is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with GNetWatch; if not, write to the Free Software
020: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
021: */
022:
023: package net.fenyo.gnetwatch.activities;
024:
025: import java.util.*;
026: import java.io.*;
027:
028: import net.fenyo.gnetwatch.*;
029: import net.fenyo.gnetwatch.GUI.*;
030: import net.fenyo.gnetwatch.actions.*;
031:
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034:
035: /**
036: * Queue is the base class for any queue.
037: * It implements the main queueing process.
038: * @author Alexandre Fenyo
039: * @version $Id: Queue.java,v 1.23 2007/03/12 05:04:15 fenyo Exp $
040: */
041:
042: public abstract class Queue extends VisualElement implements Runnable {
043: private static Log log = LogFactory.getLog(Queue.class);
044:
045: private final String name;
046: private final Config config;
047: private final Thread thread;
048: private long max_time = 0;
049:
050: // many threads access to actions
051: private final List<Action> actions = Collections
052: .synchronizedList(new LinkedList<Action>());
053:
054: // only the Queue thread accesses to localActions
055: private Vector<Action> actions_copy = null;
056:
057: private Action current_action = null;
058:
059: /**
060: * Constructor.
061: * @param name queue name.
062: * @param config configuration.
063: */
064: // main thread
065: protected Queue(final String name, final Config config) {
066: this .name = name;
067: this .config = config;
068: setType("task queue");
069: setItem(name);
070: setDescription("iterative queue");
071: thread = new Thread(this , name);
072: thread.start();
073: }
074:
075: /**
076: * Sets the current GUI instance.
077: * @param GUI current GUI instance.
078: * @return void.
079: */
080: // final because called by constructor (by means of setItem())
081: protected final void initialize(final GUI gui) {
082: super .initialize(gui);
083: if (gui != null)
084: setImageQueue();
085: }
086:
087: /**
088: * Returns the size of the queue.
089: * @param none.
090: * @return int size.
091: */
092: public int size() {
093: return actions.size();
094: }
095:
096: /**
097: * Adds a new action to this queue.
098: * @param action new action to add.
099: * @return void.
100: */
101: // GUI thread
102: public void addAction(final Action action) {
103: actions.add(action);
104: }
105:
106: /**
107: * Removes an action from this queue.
108: * @param action action to remove.
109: * @return void.
110: */
111: // GUI thread
112: public void removeAction(final Action action) {
113: actions.remove(action);
114: }
115:
116: /**
117: * Called after each cycle.
118: * @param none.
119: * @return void.
120: */
121: // Queue thread
122: protected void informCycle() {
123: }
124:
125: /**
126: * Returns the time to wait after each cycle.
127: * @param none.
128: * @return int time to wait.
129: */
130: // Queue thread
131: abstract protected int getCycleDelay();
132:
133: /**
134: * Returns the time to wait between empty cycles.
135: * @param none.
136: * @return time to wait.
137: */
138: // Queue thread
139: abstract protected int getEmptyCycleDelay();
140:
141: /**
142: * Returns the time to wait between two actions.
143: * @param none.
144: * @return time to wait.
145: */
146: // Queue thread
147: abstract protected int getActionDelay();
148:
149: /**
150: * Loops among the actions currently in this queue.
151: * @param none.
152: * @return void.
153: */
154: // Queue thread
155: public void run() {
156: int nactions = 0;
157: int ncurrent = 0;
158:
159: if (actions_copy == null || actions_copy.isEmpty())
160: synchronized (actions) {
161: actions_copy = new Vector<Action>(actions);
162: nactions = actions_copy.size();
163: ncurrent = 0;
164: setProgress(0);
165: }
166:
167: while (!config.isEnd()) {
168: if (!actions_copy.isEmpty()) {
169: Action action = actions_copy.get(0);
170: actions_copy.remove(0);
171:
172: if (nactions != 0)
173: setProgress(Math.min(100 * ++ncurrent / nactions,
174: 100));
175:
176: try {
177: synchronized (this ) {
178: max_time = new Date().getTime()
179: + action.getMaxDelay();
180: current_action = action;
181: }
182:
183: // this thread may be interrupted by the Background thread only from here ...
184: action.invoke();
185:
186: } catch (final IOException ex) {
187: log.warn("Exception", ex);
188: } catch (final InterruptedException ex) {
189: } finally {
190: synchronized (this ) {
191: max_time = 0;
192: current_action = null;
193: // ... to there
194: }
195: }
196: }
197:
198: if (actions_copy.isEmpty()) {
199: informCycle();
200: synchronized (actions) {
201: actions_copy = new Vector<Action>(actions);
202: nactions = actions_copy.size();
203: ncurrent = 0;
204: setProgress(0);
205: }
206: try {
207: Thread
208: .sleep(actions_copy.size() != 0 ? getCycleDelay()
209: : getEmptyCycleDelay());
210: } catch (final InterruptedException ex) {
211: // each time a timeout occurs, the background thread interrupts this thread
212: }
213: }
214:
215: try {
216: Thread.sleep(getActionDelay());
217: } catch (final InterruptedException ex) {
218: // each time a timeout occurs, the background thread interrupts this thread
219: }
220: }
221: }
222:
223: /**
224: * Checks that the timeout occured.
225: * @param none.
226: * @return boolean true if timeout occured.
227: */
228: // Background thread
229: public synchronized boolean isExhausted() {
230: return max_time == 0 ? false : new Date().getTime() > max_time;
231: }
232:
233: /**
234: * Stops this queue thread.
235: * @param none.
236: * @return void.
237: * @throws InterruptedException exception.
238: */
239: // main thread
240: public void end() throws InterruptedException {
241: try {
242: interrupt(Action.InterruptCause.exiting);
243: } catch (final IOException ex) {
244: log.warn("Exception", ex);
245: }
246:
247: thread.join();
248: }
249:
250: /**
251: * Stops this queue thread.
252: * @param cause cause.
253: * @return void.
254: * @throws InterruptedException exception.
255: */
256: // main & Background thread
257: public void interrupt(final Action.InterruptCause cause)
258: throws IOException {
259: if (thread != null) {
260: thread.interrupt();
261: synchronized (this ) {
262: if (current_action != null)
263: current_action.interrupt(cause);
264: }
265: }
266: }
267:
268: /**
269: * Detaches this queue from the selected parent.
270: * @param visual_parent selected parent.
271: * @return void.
272: */
273: public void removeVisualElements(final VisualElement visual_parent) {
274: return;
275: }
276: }
|