001: /*
002: * CoadunationLib: The coaduntion implementation library.
003: * Copyright (C) 2006 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * CoadunationThreadGroup.java
020: *
021: * This object is responsible for loading the JMX Bean into memory from the
022: * deployment loader passed to it.
023: */
024:
025: package com.rift.coad.lib.thread;
026:
027: // the import paths
028: import java.util.Vector;
029: import java.util.List;
030: import java.util.ArrayList;
031:
032: // logging import
033: import org.apache.log4j.Logger;
034:
035: // coadunation imports
036: import com.rift.coad.lib.security.UserSession;
037: import com.rift.coad.lib.security.user.UserSessionManager;
038: import com.rift.coad.lib.configuration.ConfigurationFactory;
039: import com.rift.coad.lib.configuration.Configuration;
040: import com.rift.coad.lib.security.user.UserStoreManager;
041:
042: /**
043: * This object is responsible for controlling the creation and administration of
044: * a grouping of threads.
045: *
046: * @author Brett Chaldecott
047: */
048: public class CoadunationThreadGroup {
049:
050: /**
051: * This object contains the list of threads in memory for a grouping. It
052: */
053: public class ThreadList {
054: // the class log variable
055: protected Logger log = Logger.getLogger(ThreadList.class
056: .getName());
057:
058: // member variables
059: private boolean terminated = false;
060: private Vector threads = null;
061:
062: /**
063: * The default constructor of the thread list.
064: */
065: public ThreadList() {
066: threads = new Vector();
067: }
068:
069: /**
070: * This method adds a new thread to the list of threads.
071: *
072: * @param thread The reference to the thread to add.
073: */
074: public synchronized boolean addThread(BasicThread thread) {
075: if (terminated == false) {
076: threads.add(thread);
077: return true;
078: }
079: return false;
080: }
081:
082: /**
083: * Returns a copy of the current threads.
084: *
085: * @return The list of the current threads.
086: */
087: public synchronized Vector getThreads() {
088: Vector threads = new Vector();
089: threads.addAll(this .threads);
090: return threads;
091: }
092:
093: /**
094: * This method removes an object from the list that matches.
095: *
096: * @param thread The reference to the thread to remove.
097: */
098: public synchronized void remove(BasicThread thread) {
099: for (int index = 0; index < threads.size(); index++) {
100: if (threads.get(index) == thread) {
101: log.info("Object equal removing ["
102: + thread.getId()
103: + "] id ["
104: + ((BasicThread) threads.get(index))
105: .getId() + "]");
106: threads.remove(thread);
107: break;
108: }
109: }
110: }
111:
112: /**
113: * This method sets the terminated flag for this object.
114: */
115: public synchronized void terminate() {
116: terminated = true;
117: }
118:
119: /**
120: * This method will return true if this object is terminated
121: */
122: public synchronized boolean isTerminated() {
123: return terminated;
124: }
125: }
126:
127: // the classes constant static variables
128: private final static String THREAD_TERMINATE_TIMEOUT = "Thread_Terminate_Timeout";
129:
130: // the class log variable
131: protected Logger log = Logger
132: .getLogger(CoadunationThreadGroup.class.getName());
133:
134: // the classes private member variables
135: private UserSessionManager sessionManager = null;
136: private UserStoreManager userStoreManager = null;
137: private ThreadList threadList = null;
138: private long threadTerminateTimeout = 0;
139: private CoadunationThreadGroup parent = null;
140:
141: /**
142: *
143: * Creates a new instance of CoadunationThreadGroup
144: *
145: *
146: * @param sessionManager A reference to the user session manager.
147: * @param userStoreManager The user store object.
148: */
149: public CoadunationThreadGroup(UserSessionManager sessionManager,
150: UserStoreManager userStoreManager) throws ThreadException {
151: this .sessionManager = sessionManager;
152: this .userStoreManager = userStoreManager;
153: this .threadList = new ThreadList();
154: try {
155: Configuration config = ConfigurationFactory.getInstance()
156: .getConfig(this .getClass());
157: threadTerminateTimeout = config
158: .getLong(THREAD_TERMINATE_TIMEOUT);
159:
160: } catch (Exception ex) {
161: throw new ThreadException(
162: "Failed to retrieve default thread terminate timeout.",
163: ex);
164: }
165: }
166:
167: /**
168: *
169: * Creates a new instance of CoadunationThreadGroup
170: *
171: *
172: * @param sessionManager A reference to the user session manager.
173: * @param userStoreManager The user store object.
174: */
175: private CoadunationThreadGroup(CoadunationThreadGroup parent,
176: UserSessionManager sessionManager,
177: UserStoreManager userStoreManager) throws ThreadException {
178: if (parent == null) {
179: throw new ThreadException(
180: "The parent thread group is invalid");
181: }
182: this .parent = parent;
183: this .sessionManager = sessionManager;
184: this .userStoreManager = userStoreManager;
185: this .threadList = new ThreadList();
186: try {
187: Configuration config = ConfigurationFactory.getInstance()
188: .getConfig(this .getClass());
189: threadTerminateTimeout = config
190: .getLong(THREAD_TERMINATE_TIMEOUT);
191:
192: } catch (Exception ex) {
193: throw new ThreadException(
194: "Failed to retrieve default thread terminate timeout.",
195: ex);
196: }
197: }
198:
199: /**
200: * This method will start the required number of threads of the given class
201: * type.
202: *
203: * @param classRef The reference to the class type.
204: * @param username The name of the user.
205: * @param number The number of threads to start.
206: * @exception ThreadException
207: */
208: public void startThreads(Class classRef, String username, int number)
209: throws ThreadException {
210: try {
211: validateThreadClass(classRef);
212: for (int count = 0; count < number; count++) {
213: BasicThread threadRef = (BasicThread) classRef
214: .newInstance();
215: if (threadRef instanceof CoadunationThread) {
216: throw new ThreadException(
217: "Must inherit from Basic Thread and not Coad Thread.");
218: }
219: addThread(threadRef, username);
220: // make sure the context loader is set corretly for all
221: // newly created threads
222: threadRef.setContextClassLoader(Thread.currentThread()
223: .getContextClassLoader());
224:
225: // start the thread
226: threadRef.start();
227: }
228: } catch (Exception ex) {
229: throw new ThreadException("Failed to add threads for ["
230: + classRef.getName() + "] because :"
231: + ex.getMessage(), ex);
232: }
233: }
234:
235: /**
236: * This method will start the required number of threads of the given class
237: * type.
238: *
239: * @param threadRef The reference to the class type.
240: * @param username The name of the user.
241: * @exception ThreadException
242: */
243: public void addThread(BasicThread threadRef, String username)
244: throws ThreadException {
245: try {
246: UserSession user = userStoreManager.getUserInfo(username);
247: threadRef.setSessionManager(sessionManager);
248: threadRef.setUser(user);
249: threadRef.setCoadThreadGroup(this );
250:
251: // make sure the context loader is set corretly for all
252: // newly created threads
253: threadRef.setContextClassLoader(Thread.currentThread()
254: .getContextClassLoader());
255: } catch (Exception ex) {
256: throw new ThreadException(
257: "Failed to add a thread to this group : "
258: + ex.getMessage(), ex);
259: }
260: }
261:
262: /**
263: * This method will add a thread to this thread grouping.
264: *
265: * @return TRUE if the thread has been added false if it could not be added.
266: * @param threadRef The reference to the thread object to add.
267: * @exception ThreadException
268: */
269: protected boolean addThread(BasicThread threadRef)
270: throws ThreadException {
271: return threadList.addThread(threadRef);
272: }
273:
274: /**
275: * This method will remove the thread reference from the object.
276: *
277: * @param threadRef The reference to removed.
278: * @exception ThreadException
279: */
280: protected void removeThread(BasicThread threadRef) {
281: threadList.remove(threadRef);
282: }
283:
284: /**
285: * This method returns the parent object referenced by this object.
286: *
287: * @return The parent of this object.
288: */
289: public CoadunationThreadGroup getParent() {
290: return parent;
291: }
292:
293: /**
294: * This method returns the thread information for all the threads controlled
295: * by this object.
296: *
297: * @return The list containing the thread information.
298: */
299: public List getThreadInfo() throws ThreadException {
300: List threadInfoList = new ArrayList();
301: Vector threads = threadList.getThreads();
302: for (int i = 0; i < threads.size(); i++) {
303: BasicThread thread = (BasicThread) threads.get(i);
304: ThreadInfo threadInfo = new ThreadInfo(thread.getId(),
305: thread.getClass(), thread.getUser(), thread
306: .getState(), thread.getInfo());
307: threadInfoList.add(threadInfo);
308: }
309: return threadInfoList;
310: }
311:
312: /**
313: * This method will return the terminated flag value.
314: */
315: public boolean isTerminated() {
316: return threadList.isTerminated();
317: }
318:
319: /**
320: * This method terminates the threads being maintained by this thread
321: * grouping.
322: */
323: public synchronized void terminate() {
324:
325: // the object has already been terminated
326: if (threadList.isTerminated()) {
327: return;
328: }
329:
330: // call soft terminate on running threads.
331: threadList.terminate();
332:
333: Vector threads = threadList.getThreads();
334: for (int i = 0; i < threads.size(); i++) {
335: BasicThread thread = (BasicThread) threads.get(i);
336: try {
337: thread.terminate();
338: } catch (Exception ex) {
339: log.error("Failed to terminate thread ["
340: + thread.getId() + "] class ["
341: + thread.getClass().getName() + "] because : "
342: + ex.getMessage(), ex);
343: }
344: }
345:
346: // call join on the thread
347: for (int i = 0; i < threads.size(); i++) {
348: BasicThread thread = (BasicThread) threads.get(i);
349: try {
350: thread.join(getThreadTimeout(thread));
351: } catch (Exception ex) {
352: log.error("Failed to wait for thread ["
353: + thread.getId() + "] class ["
354: + thread.getClass().getName() + "] because : "
355: + ex.getMessage(), ex);
356: }
357: }
358:
359: // call the depricated stop method on the threads that have not stopped
360: // within the designated time
361: for (int i = 0; i < threads.size(); i++) {
362: BasicThread thread = (BasicThread) threads.get(i);
363: try {
364: if (thread.getState() != Thread.State.TERMINATED) {
365: log
366: .error("The thread ["
367: + thread.getId()
368: + "] class ["
369: + thread.getClass().getName()
370: + "] has not been terminated forcing it to stop.");
371: thread.stop();
372: }
373: } catch (Exception ex) {
374: log.error("Failed to wait for thread ["
375: + thread.getId() + "] class ["
376: + thread.getClass().getName() + "] because : "
377: + ex.getMessage(), ex);
378: }
379: }
380: }
381:
382: /**
383: * This method retrieve the thread timout period for a given object.
384: *
385: * @return The long containing the thread time out.
386: * @param obj The object to retrieve the thread timeout for.
387: */
388: private long getThreadTimeout(Object obj) {
389: try {
390: Configuration config = ConfigurationFactory.getInstance()
391: .getConfig(obj.getClass());
392: return config.getLong(THREAD_TERMINATE_TIMEOUT);
393: } catch (Exception ex) {
394: return threadTerminateTimeout;
395: }
396: }
397:
398: /**
399: * This method creates a new child thread group.
400: *
401: * @return The newly created thread group.
402: * @exception ThreadException
403: */
404: public CoadunationThreadGroup createThreadGroup()
405: throws ThreadException {
406: return new CoadunationThreadGroup(this , sessionManager,
407: userStoreManager);
408: }
409:
410: /**
411: * This method validates the class references is valid.
412: *
413: * @param classRef The class reference that is passed in for validation.
414: */
415: private void validateThreadClass(Class classRef)
416: throws ThreadException {
417: Class tempClass = classRef.getSuperclass();
418: while (tempClass != null) {
419: System.out.println("Class : " + tempClass.getName());
420: if (tempClass.getName().equals(
421: "com.rift.coad.lib.thread.BasicThread")) {
422: return;
423: }
424: tempClass = classRef.getSuperclass();
425: }
426: throw new ThreadException(
427: "This object does not inherit from BasicThread ["
428: + classRef.getName() + "]");
429: }
430: }
|