KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > controller > core > ControllerServerThread


1 /**
2  * C-JDBC: Clustered JDBC.
3  * Copyright (C) 2002-2005 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): Duncan Smith.
23  */

24
25 package org.objectweb.cjdbc.controller.core;
26
27 import java.io.IOException JavaDoc;
28 import java.net.InetAddress JavaDoc;
29 import java.net.ServerSocket JavaDoc;
30 import java.net.Socket JavaDoc;
31 import java.util.ArrayList JavaDoc;
32
33 import javax.net.ServerSocketFactory;
34
35 import org.objectweb.cjdbc.common.i18n.Translate;
36 import org.objectweb.cjdbc.common.log.Trace;
37 import org.objectweb.cjdbc.common.net.SSLException;
38 import org.objectweb.cjdbc.common.net.SocketFactoryFactory;
39 import org.objectweb.cjdbc.common.stream.CJDBCOutputStream;
40
41 /**
42  * A <code>ControllerServerThread</code> listens for C-JDBC driver
43  * connections. It accepts the connection and give them to
44  * <code>ControllerWorkerThreads</code>.
45  *
46  * @see org.objectweb.cjdbc.controller.core.ControllerWorkerThread
47  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
48  * @author <a HREF="mailto:duncan@mightybot.com">Duncan Smith </a>
49  * @version 1.0
50  */

51 public class ControllerServerThread extends Thread JavaDoc
52 {
53   private ServerSocket JavaDoc serverSocket;
54   private boolean isShuttingDown = false;
55   protected Controller controller;
56   /** Pending queue of client (driver) socket connections */
57   protected ArrayList JavaDoc controllerServerThreadPendingQueue = new ArrayList JavaDoc();
58   /**
59    * Number of idle <code>ControllerWorkerThread</code>. Access to this
60    * variable must be synchronized using pendingQueue.
61    */

62   protected int idleWorkerThreads = 0;
63
64   /** Logger instance. */
65   static Trace logger = Trace
66                                                                                 .getLogger("org.objectweb.cjdbc.controller.core.Controller");
67
68   /**
69    * Creates a new ControllerServerThread that listens on the given port.
70    *
71    * @param controller The controller which created this thread.
72    */

73   public ControllerServerThread(Controller controller)
74   {
75     super("ControllerServerThread");
76     this.controller = controller;
77
78     try
79     {
80       InetAddress JavaDoc bindAddress = InetAddress
81           .getByName(controller.getIPAddress());
82
83       // Determine if a specific IP address has been requested.
84
/**
85        * @see org.objectweb.cjdbc.controller.xml.ControllerParser#configureController(Attributes)
86        * for how controller's IPAddress is set by default.
87        */

88       if (!controller.getIPAddress().equals(
89           InetAddress.getLocalHost().getHostAddress()))
90       { // Non-default value: an IP has been specified that is not localhost...
91
// If the user has *asked for* getLocalHost().getHostAddress(), bad luck
92
// we lose.
93

94         // Build an InetAddress by passing the requested IP address to the
95
// InetAddress class constructor. This will validate the sanity of the
96
// IP by either accepting the requested value or throwing a
97
// BindException.
98
if (controller.isSecurityEnabled()
99             && controller.getSecurity().isSSLEnabled())
100         {
101           ServerSocketFactory sslFact = SocketFactoryFactory
102               .createServerFactory(controller.getSecurity().getSslConfig());
103           serverSocket = sslFact.createServerSocket(controller.getPortNumber(),
104               controller.getBacklogSize(), bindAddress);
105         }
106         else
107         {
108           serverSocket = new ServerSocket JavaDoc(controller.getPortNumber(),
109               controller.getBacklogSize(), bindAddress);
110         }
111       }
112       else
113       { // Default value: no specific IP was requested or was left as the
114
// default. Create a basic local socket.
115

116         if (controller.isSecurityEnabled()
117             && controller.getSecurity().isSSLEnabled())
118         {
119           ServerSocketFactory sslFact = SocketFactoryFactory
120               .createServerFactory(controller.getSecurity().getSslConfig());
121           serverSocket = sslFact.createServerSocket(controller.getPortNumber(),
122               controller.getBacklogSize());
123         }
124         else
125         {
126           serverSocket = new ServerSocket JavaDoc(controller.getPortNumber(),
127               controller.getBacklogSize());
128         }
129       }
130
131     }
132     catch (java.net.BindException JavaDoc e)
133     { // Thrown if an illegal IP address was specified.
134
logger.fatal(Translate.get("controller.server.thread.illegal.ip",
135           new String JavaDoc[]{controller.getIPAddress(), e.getMessage()}));
136       controller.endOfController(e);
137     }
138     catch (IOException JavaDoc e)
139     {
140       logger.fatal(Translate.get("controller.server.thread.socket.failed",
141           controller.getPortNumber() + ""));
142       controller.endOfController(e);
143     }
144     catch (SSLException e)
145     {
146       logger.fatal(Translate.get("controller.server.thread.socket.failed",
147           controller.getPortNumber() + ""));
148       controller.endOfController(e);
149     }
150     if (logger.isInfoEnabled())
151     {
152       logger.info(Translate.get("controller.server.thread.waiting.connections",
153           new String JavaDoc[]{serverSocket.getInetAddress().getHostAddress(),
154               String.valueOf(serverSocket.getLocalPort())}));
155       logger.debug(Translate.get("controller.server.thread.backlog.size", ""
156           + controller.getBacklogSize()));
157     }
158   }
159
160   /**
161    * Accepts connections from drivers, read the virtual database name and
162    * returns the connection point.
163    */

164   public void run()
165   {
166     if (controller == null)
167     {
168       logger.error(Translate.get("controller.server.thread.controller.null"));
169       isShuttingDown = true;
170     }
171
172     Socket JavaDoc clientSocket = null;
173     while (!isShuttingDown)
174     {
175       try
176       { // Accept a connection
177
clientSocket = serverSocket.accept();
178         if (isShuttingDown)
179           break;
180         if (controller.isSecurityEnabled()
181             && !controller.getSecurity().allowConnection(clientSocket))
182         {
183           String JavaDoc errmsg = Translate.get(
184               "controller.server.thread.connection.refused", clientSocket
185                   .getInetAddress().getHostName());
186           logger.warn(errmsg);
187           CJDBCOutputStream out = new CJDBCOutputStream(clientSocket);
188           out.writeBoolean(false);
189           out.writeUTF(errmsg);
190           out.flush(); // FIXME: should we .close() instead ?
191
clientSocket = null;
192           continue;
193         }
194         else
195         {
196           if (logger.isDebugEnabled())
197             logger.debug(Translate.get(
198                 "controller.server.thread.connection.accept", clientSocket
199                     .getInetAddress().getHostName()));
200         }
201         boolean createThread = false;
202         if (isShuttingDown)
203           break;
204         synchronized (controllerServerThreadPendingQueue)
205         {
206           // Add the connection to the queue
207
controllerServerThreadPendingQueue.add(clientSocket);
208           // Check if we need to create a new thread or just wake up an
209
// existing one
210
if (idleWorkerThreads == 0)
211             createThread = true;
212           else
213             // Here we notify all threads else if one thread doesn't wake up
214
// after the first notify() we will send a second notify() and
215
// one signal will be lost. So the safe way is to wake up everybody
216
// and that worker threads go back to sleep if there is no job.
217
controllerServerThreadPendingQueue.notifyAll();
218         }
219         if (createThread)
220         { // Start a new worker thread if needed
221
ControllerWorkerThread thread = new ControllerWorkerThread(this);
222           thread.start();
223           if (logger.isDebugEnabled())
224             logger.debug(Translate.get("controller.server.thread.starting"));
225         }
226       }
227       catch (IOException JavaDoc e)
228       {
229         if (!isShuttingDown)
230         {
231           logger.warn(Translate.get(
232               "controller.server.thread.new.connection.error", e), e);
233         }
234       }
235     }
236     if (logger.isInfoEnabled())
237       logger.info(Translate.get("controller.server.thread.terminating"));
238   }
239
240   /**
241    * Refuse new connection to clients and finish transaction
242    */

243   public void shutdown()
244   {
245     isShuttingDown = true;
246     // Shutting down server thread
247
try
248     {
249       serverSocket.close();
250     }
251     catch (Exception JavaDoc e)
252     {
253       logger.warn(Translate.get("controller.shutdown.server.socket.exception"),
254           e);
255     }
256
257     /*
258      * Close pending connections (not yet served by any ControllerWorkerThread)
259      * and wake up idle ControllerWorkerThreads.
260      */

261     Object JavaDoc lock = controllerServerThreadPendingQueue;
262     synchronized (lock)
263     {
264       // close pending connections
265
int nbSockets = controllerServerThreadPendingQueue.size();
266       Socket JavaDoc socket = null;
267       for (int i = 0; i < nbSockets; i++)
268       {
269         socket = (Socket JavaDoc) controllerServerThreadPendingQueue.get(i);
270         logger.info(Translate.get("controller.shutdown.client.socket", socket
271             .getInetAddress().toString()));
272
273         try
274         {
275           socket.close();
276         }
277         catch (Exception JavaDoc e)
278         {
279           logger.warn(Translate
280               .get("controller.shutdown.client.socket.exception"), e);
281         }
282       }
283
284       // wake up idle ControllerWorkerThreads,
285
// asking them to die (controllerServerThreadPendingQueue=null)
286
this.controllerServerThreadPendingQueue = null;
287       lock.notifyAll();
288     }
289   }
290
291   /**
292    * @return Returns the controllerServerThreadPendingQueue size.
293    */

294   public int getControllerServerThreadPendingQueueSize()
295   {
296     synchronized (controllerServerThreadPendingQueue)
297     {
298       return controllerServerThreadPendingQueue.size();
299     }
300   }
301
302   /**
303    * @return Returns the idleWorkerThreads.
304    */

305   public int getIdleWorkerThreads()
306   {
307     synchronized (controllerServerThreadPendingQueue)
308     {
309       return idleWorkerThreads;
310     }
311   }
312
313   /**
314    * Returns the isShuttingDown value.
315    *
316    * @return Returns the isShuttingDown.
317    */

318   public boolean isShuttingDown()
319   {
320     return isShuttingDown;
321   }
322 }
Popular Tags