001: /*
002: * This file is part of the QuickServer library
003: * Copyright (C) QuickServer.org
004: *
005: * Use, modification, copying and distribution of this software is subject to
006: * the terms and conditions of the GNU Lesser General Public License.
007: * You should have received a copy of the GNU LGP License along with this
008: * library; if not, you can download a copy from <http://www.quickserver.org/>.
009: *
010: * For questions, suggestions, bug-reports, enhancement-requests etc.
011: * visit http://www.quickserver.org
012: *
013: */
014:
015: package org.quickserver.util.pool.thread;
016:
017: import java.util.logging.*;
018: import java.util.*;
019: import org.quickserver.util.MyString;
020: import org.quickserver.net.server.ClientHandler;
021: import org.quickserver.net.server.ClientEvent;
022:
023: /**
024: * This is the worker thread used to handle clients using
025: * {@link org.quickserver.net.server.ClientHandler}
026: * @author Akshathkumar Shetty
027: * @since 1.3
028: */
029: public class ClientThread extends Thread {
030: private static Logger logger = Logger.getLogger(ClientThread.class
031: .getName());
032: private static Map idMap = new HashMap();
033:
034: private String name = "<ClientThread-Pool#";
035: private ClientPool pool;
036: private Runnable client;
037: private int id;
038: private boolean ready = false;
039:
040: /**
041: * Holds the current Thread state. <code><pre>
042: U = Unknown
043: S = Started
044: R - Running a client
045: I = Idle
046: L = Looking for client
047: P = Was sent back to pool
048: W = Waiting in pool
049: N = Was notified, Looking for client
050: D = Dead
051: </pre></code>
052: */
053: protected volatile char state = 'U';
054:
055: public boolean isReady() {
056: return ready;
057: }
058:
059: public void clean() {
060: client = null;
061: }
062:
063: public ClientThread(ClientPool pool) {
064: this (pool, -1);
065: }
066:
067: static class InstanceId {
068: private int id = 0;
069:
070: public int getNextId() {
071: return ++id;
072: }
073: };
074:
075: private static int getNewId(int instanceCount) {
076: InstanceId instanceId = (InstanceId) idMap.get(""
077: + instanceCount);
078: if (instanceId == null) {
079: instanceId = new InstanceId();
080: idMap.put("" + instanceCount, instanceId);
081: }
082: return instanceId.getNextId();
083: }
084:
085: public ClientThread(ClientPool pool, int instanceCount) {
086: id = getNewId(instanceCount);
087: name = name + instanceCount + "-ID:" + id + ">";
088: this .pool = pool;
089: setName(name);
090: }
091:
092: public int getInstanceId() {
093: return id;
094: }
095:
096: private void executeClient() {
097: boolean niowriteFlag = false;
098: state = 'R';
099:
100: if (ClientHandler.class.isInstance(client)) {
101: niowriteFlag = ((ClientHandler) client)
102: .isClientEventNext(ClientEvent.WRITE);
103: if (niowriteFlag) {
104: pool.nioWriteStart();
105: }
106: } else {
107: niowriteFlag = false;
108: }
109:
110: try {
111: client.run();
112: } catch (RuntimeException e) {
113: logger.warning("RuntimeException @ thread run() : "
114: + getName() + ": " + MyString.getStackTrace(e));
115: } finally {
116: if (niowriteFlag) {
117: pool.nioWriteEnd();
118: }
119: }
120: state = 'I';
121: }
122:
123: public void run() {
124: state = 'S';
125:
126: if (pool.isClientAvailable() == true) {
127: ready = true;
128: synchronized (pool) {
129: pool.notify();
130: }
131: }
132:
133: boolean returnToPool = false;
134: while (true) {
135: if (ready) {
136: state = 'L';
137: client = pool.getClient();
138: if (client == null) {
139: logger
140: .fine("ClientPool returned a null client! Other Thread must have taken my client.. Ok");
141: } else {
142: executeClient();
143: logger.finest("Client returned the thread: "
144: + getName());
145: client = null;
146: if (pool == null) {
147: logger
148: .fine("Could not returning client thread "
149: + getName()
150: + ", pool was null!");
151: state = 'D';
152: break;
153: }
154: }
155:
156: if (pool.isClientAvailable() == true) {
157: state = 'L';
158: continue;
159: }
160:
161: returnToPool = true;
162: } //end if ready
163:
164: synchronized (this ) {
165: if (ready == false)
166: ready = true;
167:
168: if (returnToPool) {
169: logger.finest("Returning client thread to pool: "
170: + getName());
171: pool.returnObject(ClientThread.this );
172: returnToPool = false;
173: state = 'P';
174: }
175:
176: try {
177: state = 'W';
178: wait();
179: state = 'N';
180: } catch (InterruptedException e) {
181: logger.finest("Closing thread "
182: + Thread.currentThread().getName()
183: + " since interrupted.");
184: state = 'D';
185: break;
186: }
187: }
188: }//end while
189: }
190:
191: /**
192: * Returns the {@link org.quickserver.net.server.ClientHandler} beeing
193: * run by the ClientThread.
194: * @since 1.3.1
195: */
196: public Runnable getThread() {
197: return client;
198: }
199:
200: /**
201: * [ThreadInPool[<Instance Count>]:<id>] - <state> - Client {ClientHandler:...}
202: * @since 1.4.1
203: */
204: public String toString() {
205: return super .toString() + " - " + state + " - Client " + client;
206: }
207: }
|