KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > loadbalancer > tasks > AbstractTask


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Contact: c-jdbc@objectweb.org
6  *
7  * This library is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by the
9  * Free Software Foundation; either version 2.1 of the License, or any later
10  * version.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20  *
21  * Initial developer(s): Emmanuel Cecchet.
22  * Contributor(s): Jaco Swart.
23  */

24
25 package org.objectweb.cjdbc.controller.loadbalancer.tasks;
26
27 import java.sql.ResultSet JavaDoc;
28 import java.sql.SQLException JavaDoc;
29 import java.util.ArrayList JavaDoc;
30
31 import org.objectweb.cjdbc.common.exceptions.SQLExceptionFactory;
32 import org.objectweb.cjdbc.controller.loadbalancer.BackendWorkerThread;
33
34 /**
35  * Defines an abstract task to be processed by a
36  * <code>BackendWorkerThread</code>.
37  *
38  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
39  * @author <a HREF="mailto:jaco.swart@iblocks.co.uk">Jaco Swart </a>
40  * @version 1.0
41  */

42 public abstract class AbstractTask
43 {
44   //
45
// How the code is organized ?
46
// 1. Member variables
47
// 2. Constructor(s)
48
// 3. Task management
49
// 4. Getter/Setter
50
//
51

52   /** Total number of threads. */
53   private int totalNb;
54
55   /** Number of threads that must succeed before returning. */
56   private int nbToComplete;
57
58   /** Number of thread that have started the execution of the task */
59   private int executionStarted;
60   /** Number of backendThread that have succeeded */
61   private int success = 0;
62   /** Number of backendThread that have failed */
63   private int failed = 0;
64   /** List of exceptions of failed nodes */
65   private ArrayList JavaDoc exceptions = null;
66
67   // Internal tid flag used by BackendWorkerThread
68
private boolean hasTid = false;
69
70   // ResultSet for getting back autogenerated keys in an update with keys
71
private ResultSet JavaDoc generatedKeysResultSet;
72
73   // True if the timeout has expired on this task
74
private boolean timeoutExpired = false;
75
76   /*
77    * Constructor
78    */

79
80   /**
81    * Sets the number of threads among the total number of threads that must
82    * successfully complete the execution of this AbstractTask before returning.
83    *
84    * @param nbToComplete number of threads that must succeed before returning
85    * @param totalNb total number of threads
86    */

87   public AbstractTask(int nbToComplete, int totalNb)
88   {
89     this.nbToComplete = nbToComplete;
90     this.totalNb = totalNb;
91     success = 0;
92     failed = 0;
93     executionStarted = 0;
94   }
95
96   /*
97    * Task management
98    */

99
100   /**
101    * The task code executed by the backendThread.
102    *
103    * @param backendThread The backend thread executing this task
104    * @throws SQLException if an error occurs
105    */

106   public void execute(BackendWorkerThread backendThread) throws SQLException JavaDoc
107   {
108     synchronized (this)
109     {
110       // If the task has expired and nobody has executed it yet, we ignore it
111
// else we have to play it.
112
// Note that the exception corresponding to the timeout is set by the
113
// caller of setExpiredTimeout.
114
if (timeoutExpired && (executionStarted == 0))
115         return;
116       this.executionStarted++;
117     }
118     executeTask(backendThread);
119     // Completed executions are handled by the task internal code that calls
120
// notifyFailure or notifySuccess.
121
}
122
123   /**
124    * The implementation specific task code to be executed by backendThread.
125    *
126    * @param backendThread The backend thread executing this task
127    * @throws SQLException if an error occurs
128    */

129   public abstract void executeTask(BackendWorkerThread backendThread)
130       throws SQLException JavaDoc;
131
132   /**
133    * Notifies the successful completion of this task.
134    */

135   public synchronized void notifySuccess()
136
137   {
138     success++;
139
140     // Notify if needed
141
if ((success == nbToComplete) || (success + failed == totalNb))
142     {
143       if (failed > 0)
144         notifyAll(); // Notify all failed threads too
145
else
146         notify();
147     }
148   }
149
150   /**
151    * This is used to notify the completion of this task without success or
152    * failure. This is usually used when the task has been discarded for example
153    * by a backend that is currently disabling but still needs to execute the
154    * remaining queries in open transactions.
155    * <p>
156    * Therefore, this only decrements by one the number of threads that needs to
157    * complete.
158    */

159   public synchronized void notifyCompletion()
160   {
161     totalNb--;
162     // Notify if needed
163
if (success + failed == totalNb)
164     {
165       notifyAll(); // Notify all failed threads
166
}
167   }
168
169   /**
170    * Notifies that the specified backendThread failed to execute this task. If
171    * all nodes failed, this method return <code>false</code> meaning that the
172    * problem was due to the task and not to the thread. If the method returns
173    * <code>true</code>, it can mean that this thread failed and is no more
174    * coherent, therefore the backend associated to this thread should be
175    * disabled.
176    *
177    * @param backendThread the backend thread that has failed
178    * @param timeout time in milliseconds to wait for other threads to signal
179    * success or failure
180    * @param e the exception causing the failure
181    * @return <code>true</code> if at least one node succeeded to execute this
182    * task, <code>false</code> if all threads failed
183    * @throws SQLException if an error occured in the notification process
184    */

185   public synchronized boolean notifyFailure(BackendWorkerThread backendThread,
186       long timeout, Exception JavaDoc e) throws SQLException JavaDoc
187   {
188     failed++;
189
190     // Log the exception
191
if (exceptions == null)
192       exceptions = new ArrayList JavaDoc();
193     if (e instanceof SQLException JavaDoc)
194     {
195       SQLException JavaDoc sqlEx = (SQLException JavaDoc) e;
196       exceptions.add(SQLExceptionFactory.getSQLException(sqlEx,
197           "BackendThread " + backendThread.getBackend().getName() + " failed ("
198               + sqlEx.getLocalizedMessage() + ")"));
199     }
200     else
201       exceptions.add(new SQLException JavaDoc("BackendThread "
202           + backendThread.getBackend().getName() + " failed ("
203           + e.getLocalizedMessage() + ")").initCause(e));
204
205     // Notify if needed
206
if (success + failed == totalNb)
207     {
208       notifyAll(); // Notify all failed threads
209
}
210     else
211     {
212       try
213       { // Wait to check if all other threads failed or not
214
wait(timeout);
215       }
216       catch (InterruptedException JavaDoc ie)
217       {
218         throw (SQLException JavaDoc) new SQLException JavaDoc(
219             "Wait interrupted() in failed task of backend "
220                 + backendThread.getBackend().getName() + " ("
221                 + e.getLocalizedMessage() + ")").initCause(e);
222       }
223     }
224     return success > 0;
225   }
226
227   //
228
// Getter/Setter
229
//
230

231   /**
232    * Returns the exceptions lists.
233    *
234    * @return an <code>ArrayList</code>
235    */

236   public ArrayList JavaDoc getExceptions()
237   {
238     return exceptions;
239   }
240
241   /**
242    * Returns the number of threads that have started the execution of the task.
243    *
244    * @return Returns the number of started executions.
245    */

246   public synchronized int getExecutionStarted()
247   {
248     return executionStarted;
249   }
250
251   /**
252    * Returns the failed.
253    *
254    * @return an <code>int</code> value
255    */

256   public int getFailed()
257   {
258     return failed;
259   }
260
261   /**
262    * Returns the number of threads that must succeed before returning.
263    *
264    * @return an <code>int</code> value
265    */

266   public int getNbToComplete()
267   {
268     return nbToComplete;
269   }
270
271   /**
272    * Returns the success.
273    *
274    * @return an <code>int</code> value
275    */

276   public int getSuccess()
277   {
278     return success;
279   }
280
281   /**
282    * Returns the total number of threads.
283    *
284    * @return an <code>int</code> value
285    * @see #setTotalNb
286    */

287   public int getTotalNb()
288   {
289     return totalNb;
290   }
291
292   /**
293    * Sets the total number of threads.
294    *
295    * @param totalNb the total number of threads to set
296    * @see #getTotalNb
297    */

298   public void setTotalNb(int totalNb)
299   {
300     this.totalNb = totalNb;
301   }
302
303   /**
304    * Returns true if the task has been sucessfully completed by nbToComplete
305    * nodes (set in the constructor) of if everyone has completed (succesfully or
306    * not), false otherwise.
307    *
308    * @return true if the task execution is complete
309    * @see AbstractTask#AbstractTask(int, int)
310    */

311   public synchronized boolean hasCompleted()
312   {
313     return ((success >= nbToComplete) || (success + failed == totalNb));
314   }
315
316   /**
317    * Returns true if the task has completed (succesfully or not) or false if we
318    * are still expecting answers from some backends.
319    *
320    * @return true if the task execution is complete
321    */

322   public synchronized boolean hasFullyCompleted()
323   {
324     return success + failed == totalNb;
325   }
326
327   /**
328    * Returns true if this task has a tid attached to it.
329    * <p>
330    * Used internally by BackendWorkerThread.
331    *
332    * @return Returns the hasTid.
333    */

334   public boolean hasTid()
335   {
336     return hasTid;
337   }
338
339   /**
340    * Sets the hasTid value.
341    * <p>
342    * Used internally by BackendWorkerThread.
343    *
344    * @param hasTid The hasTid to set.
345    */

346   public void setHasTid(boolean hasTid)
347   {
348     this.hasTid = hasTid;
349   }
350
351   /**
352    * Returns the generatedKeysResultSet value.
353    *
354    * @return Returns the generatedKeysResultSet.
355    */

356   public ResultSet JavaDoc getGeneratedKeysResultSet()
357   {
358     return generatedKeysResultSet;
359   }
360
361   /**
362    * Sets the generatedKeysResultSet value.
363    *
364    * @param generatedKeysResultSet The generatedKeysResultSet to set.
365    */

366   public void setGeneratedKeysResultSet(ResultSet JavaDoc generatedKeysResultSet)
367   {
368     this.generatedKeysResultSet = generatedKeysResultSet;
369   }
370
371   /**
372    * Set the flag to tell that the timeout has expired on this task. If no
373    * backend has started the task execution then the task will be canceled and
374    * the method will return true. Otherwise, all backends will execute the
375    * request and the method will return false.
376    *
377    * @return true if BackendThreads will ignore the task, false if all backends
378    * will execute the task.
379    */

380   public synchronized boolean setExpiredTimeout()
381   {
382     this.timeoutExpired = true;
383     return executionStarted == 0;
384   }
385
386 }
387
Popular Tags