KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > core > ControllerServerThread


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2002-2004 French National Institute For Research In Computer
4  * Science And Control (INRIA).
5  * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
6  * Contact: sequoia@continuent.org
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * Initial developer(s): Emmanuel Cecchet.
21  * Contributor(s): Duncan Smith.
22  */

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

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

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

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

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

95         // Build an InetAddress by passing the requested IP address to the
96
// InetAddress class constructor. This will validate the sanity of the
97
// IP by either accepting the requested value or throwing a
98
// BindException.
99
if (controller.getSslConfiguration() != null)
100         {
101           ServerSocketFactory sslFact = SocketFactoryFactory
102               .createServerFactory(controller.getSslConfiguration());
103           serverSocket = sslFact.createServerSocket(controller
104               .getJdbcPortNumber(), controller.getBacklogSize(), bindAddress);
105         }
106         else
107         {
108           serverSocket = new ServerSocket JavaDoc(controller.getJdbcPortNumber(),
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.getSslConfiguration() != null)
117         {
118           ServerSocketFactory sslFact = SocketFactoryFactory
119               .createServerFactory(controller.getSslConfiguration());
120           serverSocket = sslFact.createServerSocket(controller
121               .getJdbcPortNumber(), controller.getBacklogSize());
122         }
123         else
124         {
125           serverSocket = new ServerSocket JavaDoc(controller.getJdbcPortNumber(),
126               controller.getBacklogSize());
127         }
128       }
129
130     }
131     catch (java.net.BindException JavaDoc e)
132     { // Thrown if an illegal IP address was specified.
133
String JavaDoc msg = Translate.get("controller.server.thread.illegal.ip",
134           new String JavaDoc[]{controller.getIPAddress(), e.getMessage()});
135       logger.fatal(msg);
136       endUserLogger.fatal(msg);
137       controller.endOfController(e);
138     }
139     catch (IOException JavaDoc e)
140     {
141       String JavaDoc msg = Translate.get("controller.server.thread.socket.failed",
142           new String JavaDoc[]{String.valueOf(controller.getJdbcPortNumber()),
143               e.getMessage()});
144       if (logger.isDebugEnabled())
145         logger.fatal(msg, e);
146       else
147         logger.fatal(msg);
148       endUserLogger.fatal(msg);
149       controller.endOfController(e);
150     }
151     catch (SSLException e)
152     {
153       String JavaDoc msg = Translate.get("controller.server.thread.socket.failed",
154           new String JavaDoc[]{String.valueOf(controller.getJdbcPortNumber()),
155               e.getMessage()});
156       if (logger.isDebugEnabled())
157         logger.fatal(msg, e);
158       else
159         logger.fatal(msg);
160       endUserLogger.fatal(msg);
161       controller.endOfController(e);
162     }
163     if (logger.isInfoEnabled())
164     {
165       logger.info(Translate.get("controller.server.thread.waiting.connections",
166           new String JavaDoc[]{serverSocket.getInetAddress().getHostAddress(),
167               String.valueOf(serverSocket.getLocalPort())}));
168       logger.debug(Translate.get("controller.server.thread.backlog.size", ""
169           + controller.getBacklogSize()));
170     }
171   }
172
173   /**
174    * Accepts connections from drivers, read the virtual database name and
175    * returns the connection point.
176    */

177   public void run()
178   {
179     if (controller == null)
180     {
181       logger.error(Translate.get("controller.server.thread.controller.null"));
182       isShuttingDown = true;
183     }
184
185     Socket JavaDoc clientSocket = null;
186     while (!isShuttingDown)
187     {
188       try
189       { // Accept a connection
190
clientSocket = serverSocket.accept();
191         if (isShuttingDown)
192           break;
193
194         // No more access control here, delegated to the
195
// VirtualDatabaseWorkerThread.
196

197         boolean createThread = false;
198         if (isShuttingDown)
199           break;
200         synchronized (controllerServerThreadPendingQueue)
201         {
202           // Add the connection to the queue
203
controllerServerThreadPendingQueue.add(clientSocket);
204           // Check if we need to create a new thread or just wake up an
205
// existing one
206
if (idleWorkerThreads == 0)
207             createThread = true;
208           else
209             // Here we notify all threads else if one thread doesn't wake up
210
// after the first notify() we will send a second notify() and
211
// one signal will be lost. So the safe way is to wake up everybody
212
// and that worker threads go back to sleep if there is no job.
213
controllerServerThreadPendingQueue.notifyAll();
214         }
215         if (createThread)
216         { // Start a new worker thread if needed
217
ControllerWorkerThread thread = new ControllerWorkerThread(this);
218           thread.start();
219           if (logger.isDebugEnabled())
220             logger.debug(Translate.get("controller.server.thread.starting"));
221         }
222       }
223       catch (IOException JavaDoc e)
224       {
225         if (!isShuttingDown)
226         {
227           logger.warn(Translate.get(
228               "controller.server.thread.new.connection.error", e), e);
229         }
230       }
231     }
232     if (logger.isInfoEnabled())
233       logger.info(Translate.get("controller.server.thread.terminating"));
234   }
235
236   /**
237    * Refuse new connection to clients and finish transaction
238    */

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

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

290   public int getControllerServerThreadPendingQueueSize()
291   {
292     synchronized (controllerServerThreadPendingQueue)
293     {
294       return controllerServerThreadPendingQueue.size();
295     }
296   }
297
298   /**
299    * @return Returns the idleWorkerThreads.
300    */

301   public int getIdleWorkerThreads()
302   {
303     synchronized (controllerServerThreadPendingQueue)
304     {
305       return idleWorkerThreads;
306     }
307   }
308
309   /**
310    * Returns the isShuttingDown value.
311    *
312    * @return Returns the isShuttingDown.
313    */

314   public boolean isShuttingDown()
315   {
316     return isShuttingDown;
317   }
318 }
Popular Tags