KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > server > ss > ASSocketService


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23 package com.sun.enterprise.server.ss;
24
25 import java.io.IOException JavaDoc;
26 import java.net.InetAddress JavaDoc;
27 import java.net.InetSocketAddress JavaDoc;
28 import java.net.ServerSocket JavaDoc;
29 import java.net.Socket JavaDoc;
30 import java.nio.channels.SelectionKey JavaDoc;
31 import java.nio.channels.Selector JavaDoc;
32 import java.nio.channels.ServerSocketChannel JavaDoc;
33 import java.nio.channels.SocketChannel JavaDoc;
34 import java.nio.channels.spi.SelectorProvider JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.logging.Level JavaDoc;
38 import java.util.logging.Logger JavaDoc;
39 import com.sun.enterprise.server.PEMain;
40 import com.sun.enterprise.server.ondemand.entry.EntryPoint;
41 import com.sun.enterprise.server.ondemand.entry.ServerEntryHelper;
42 import com.sun.enterprise.server.ss.provider.ASSelectorProvider;
43 import com.sun.enterprise.server.ss.provider.ASServerSocket;
44 import com.sun.enterprise.server.ss.provider.PortConflictException;
45 import com.sun.enterprise.util.i18n.StringManager;
46 import com.sun.logging.LogDomains;
47
48 /**
49  * One each ASSocketService will be used for each port opened in domain.xml.
50  * It binds a port so that the client will not get exception when it tries to
51  * access the port.
52  */

53 public class ASSocketService implements EntryPoint {
54
55     private static Logger JavaDoc logger = LogDomains.getLogger(LogDomains.CORE_LOGGER);
56     private static StringManager localStrings =
57         StringManager.getManager( ASSocketService.class);
58
59     private static HashMap JavaDoc<Integer JavaDoc, ASSocketService> managedPortsTable =
60             new HashMap JavaDoc<Integer JavaDoc, ASSocketService>();
61     private static PEMain peMain = null;
62     private static InetAddress JavaDoc localHost = null;
63
64     private static final String JavaDoc SO_REUSEADDR_PROPERTY =
65             "com.sun.enterprise.server.ss.setReuseAddress";
66     private static boolean setReuseAddress =
67              new Boolean JavaDoc(System.getProperty(SO_REUSEADDR_PROPERTY));
68
69     private ServerSocket JavaDoc ss;
70     private ServerSocketChannel JavaDoc sschan;
71     private Selector JavaDoc sel;
72
73     private static final int TIMEOUT = 30 * 1000; // 30 seconds.
74
private static boolean triggered = false;
75
76     static final int NOTSTARTED = 0;
77     static final int SERVICENOTIFIED = 1;
78     static final int STARTING = 2;
79     static final int STARTED = 3;
80     private int state = NOTSTARTED;
81
82     private static Object JavaDoc lock = new Object JavaDoc();
83     private Object JavaDoc acceptLock = new Object JavaDoc();
84     private ASSocketServiceConfig config = null;
85
86     ASSocketService(ASSocketServiceConfig config) {
87         this.config = config;
88     if ( localHost == null ) {
89         try {
90         localHost = InetAddress.getLocalHost();
91         } catch ( Exception JavaDoc ex ) {}
92     }
93     }
94
95     void start() throws PortConflictException {
96         try {
97             config.init();
98             _initializeService();
99             Selector JavaDoc select = createListeningSelector();
100             (new EntryPointThread(select)).start();
101
102             if ( logger.isLoggable(Level.FINE) ) {
103                 logger.fine("ASSocketService Successfully started for " + config);
104             }
105         } catch(IOException JavaDoc ie){
106             String JavaDoc i18nMsg = localStrings.getString(
107                 "socketservice.port_conflict", new Object JavaDoc[]{String.valueOf(config.getPort())});
108             throw new PortConflictException(config.getPort(),i18nMsg, ie);
109         }
110     }
111
112     void _reInitializeService() throws IOException JavaDoc {
113         ASSelectorProvider provider =
114         (ASSelectorProvider) SelectorProvider.provider();
115         provider.clear(config.getPort());
116         synchronized (managedPortsTable) {
117         // put the port in stable so that exists(port) returns true
118
managedPortsTable.remove(config.getPort());
119         }
120
121         try {
122             if (this.sel != null) {
123                 this.sel.close();
124             }
125         } catch (Exception JavaDoc e) {
126             logger.log(Level.FINEST, e.getMessage(), e);
127         }
128
129         int oldPort = config.getPort();
130         config.init();
131         /** In retrospect, the reInitialization is not that necessary.
132             Commenting this out for now. Keeping this code within
133             the comment so that it can be turned on later.
134
135             Reinitialization will be required, when we automatically
136             stop containers that are idle.
137         if (config.getPort() == oldPort) {
138             _initializeService();
139         }
140         **/

141     }
142
143     void _initializeService() throws IOException JavaDoc {
144          synchronized (managedPortsTable) {
145          // put the port in stable so that exists(port) returns true
146
managedPortsTable.put(config.getPort(), this);
147          }
148      // open channel and bind its ServerSocket
149
sschan = ServerSocketChannel.open();
150          ss = sschan.socket();
151          if (setReuseAddress) {
152              ss.setReuseAddress(true);
153          }
154          ss.bind(config.getSocketAddress());
155     }
156
157     static boolean close(int port, ServerSocket JavaDoc sock, ServerSocketChannel JavaDoc channel)
158     throws IOException JavaDoc {
159
160         ASSocketService savedSS = null;
161         if (port > 0) {
162             savedSS = ASSocketService.get(port);
163             if (savedSS != null) { //If managed by socket service
164
if (savedSS.entryBeingProcessed()) {
165                     // Return and dont close
166
ASSelectorProvider pr = (ASSelectorProvider)
167                     SelectorProvider.provider();
168                     pr.setPortState(port, ASSelectorProvider.PORT_BOUND);
169                     return false;
170                 }
171             }
172         }
173
174         boolean closed = false;
175         try {
176             if (channel != null) {
177                 if (channel.isOpen()) {
178                     closed = true;
179                     channel.close();
180                 }
181             }
182             if (sock != null) {
183                 if (sock.isClosed() == false) {
184                     closed = true;
185                     sock.close();
186                 }
187             }
188         } finally {
189             if (savedSS != null && closed) {
190                 ASSocketService.reInitializeService(port);
191             }
192         }
193
194         return true;
195         
196     }
197
198     static void reInitializeService(int port) throws IOException JavaDoc {
199         ASSocketService savedSS = ASSocketService.get(port);
200         if (savedSS != null) {
201             savedSS._reInitializeService();
202         }
203     }
204
205     Selector JavaDoc createListeningSelector() {
206         try {
207             sschan.configureBlocking(false);
208             this.sel = Selector.open();
209             sschan.register(sel, SelectionKey.OP_ACCEPT);
210         } catch (Exception JavaDoc e) {
211             logger.log(Level.SEVERE, e.getMessage(), e);
212         }
213         return this.sel;
214     }
215
216     static void removeListeningSelector(int port) {
217         try {
218             ASSocketService savedSS = get(port);
219             savedSS.sel.close();
220             savedSS.sschan.configureBlocking(true);
221         } catch (Exception JavaDoc e) {
222             logger.log(Level.SEVERE, e.getMessage(), e);
223         }
224     }
225
226     static ServerSocket JavaDoc getServerSocket(int port) {
227         ASSocketService a = managedPortsTable.get(port);
228         return a.ss;
229     }
230
231
232     static ServerSocketChannel JavaDoc getServerSocketChannel(int port) {
233         ASSocketService a = managedPortsTable.get(port);
234         return a.sschan;
235     }
236
237     static boolean exists(int port) {
238         return managedPortsTable.containsKey(port);
239     }
240
241     static ASSocketService get(int port) {
242         return managedPortsTable.get(port);
243     }
244
245     static void initialize() {
246     if ( peMain == null ) {
247         peMain = com.sun.enterprise.server.PEMain.getInstance();
248     }
249     }
250
251     boolean entryBeingProcessed() {
252         return state != STARTED;
253     }
254
255     public static boolean socketServiceNotified(int port) {
256         ASSocketService ss = ASSocketService.get(port);
257         if (ss != null) {
258             return ss._socketServiceNotified(port);
259         } else {
260             return true;
261         }
262     }
263
264     boolean _socketServiceNotified(int port) {
265         if (state == NOTSTARTED) {
266             // No one has started it so far.
267
if (!ServerEntryHelper.isNotifiedByPortEntryContext(port)) {
268                 state = SERVICENOTIFIED;
269                 return false;
270             }
271         }
272         return true;
273     }
274
275     public void generateEntryContext(Object JavaDoc context) {
276         if ( logger.isLoggable(Level.FINE) ) {
277          logger.fine("In ASSocketService.generateEntryContext for context " + context);
278         }
279         ServerEntryHelper.generatePortEntryContext((Integer JavaDoc) context);
280     }
281
282     static void waitOnAccept(SocketChannel JavaDoc sc) {
283         // Redundant peMain.isStartingUp() is required since sc.socket()
284
// has to pass thru a synchronization.
285
if ( peMain.isStartingUp() ) {
286             waitOnAccept(sc.socket());
287         } else {
288             waitForServiceStartUp(sc.socket());
289         }
290
291     }
292
293     // If server is starting up & socket is connected to a client outside this JVM
294
// & socket is bound to a "managed port", then wait till startup completes.
295
// This is necessary to prevent incoming requests from being processed before
296
// all modules in the appserver have been initialized.
297
static void waitOnAccept(Socket JavaDoc s) {
298     if ( peMain.isStartingUp() ) {
299         int localPort = s.getLocalPort();
300         if ( !exists(localPort) ) { // Check if port is managed
301
return;
302         }
303
304         // If client is in this JVM, dont wait
305
Integer JavaDoc remotePort = new Integer JavaDoc(s.getPort());
306         synchronized ( peMain ) {
307             while ( peMain.isStartingUp() && ! hasClientSocketLocalPorts(s) ) {
308                     if ( logger.isLoggable(Level.FINE) ) {
309                 logger.fine("In ASSocketService.waitOnAccept for localport " + localPort);
310                     }
311             try {
312             peMain.wait();
313             } catch ( Exception JavaDoc ex ) {}
314             }
315         }
316     }
317
318         waitForServiceStartUp(s);
319     }
320
321     static void waitForServiceStartUp(Socket JavaDoc s) {
322         ASSocketService savedService = get(s.getLocalPort());
323         if ( savedService != null ) {
324             savedService._waitForServiceStartUp(s);
325         }
326     }
327
328     // When a service is being started and
329
// if a client request come for that service, wait
330
// until the processing the entry has been processed
331
// completely.
332
void _waitForServiceStartUp(Socket JavaDoc s) {
333     if ( entryBeingProcessed() ) {
334         int localPort = s.getLocalPort();
335
336         // If client is in this JVM, dont wait
337
Integer JavaDoc remotePort = new Integer JavaDoc(s.getPort());
338         synchronized ( acceptLock ) {
339             while ( entryBeingProcessed() &&
340                         ! ASSocketService.hasClientSocketLocalPorts(s) ) {
341                     if ( logger.isLoggable(Level.FINE) ) {
342                 logger.fine("In ASSocketService.waitForServiceStartUp for localport " + localPort);
343                     }
344             try {
345             acceptLock.wait();
346             } catch ( Exception JavaDoc ex ) {}
347             }
348         }
349     }
350
351     }
352
353     static void clientSocketConnected(Socket JavaDoc s) {
354         boolean toAdd = true;
355     if ( peMain.isStartingUp() ) {
356             if ( logger.isLoggable(Level.FINE) ) {
357             logger.fine("In ASSocketService.clientSocketConnected, adding port "
358             + s.getLocalPort());
359             }
360
361         synchronized ( peMain ) {
362                 putClientSocketLocalPort(s);
363                 toAdd = false;
364         peMain.notifyAll();
365         }
366     }
367
368         ASSocketService service = ASSocketService.get(s.getPort());
369         if (service != null && service.entryBeingProcessed()) {
370         synchronized ( service.acceptLock ) {
371                 if (toAdd) {
372                     putClientSocketLocalPort(s);
373                 }
374             service.acceptLock.notifyAll();
375        }
376         }
377
378     }
379
380     static void putClientSocketLocalPort(Socket JavaDoc s) {
381         int serverPort = s.getPort();
382         if (exists(serverPort)) {
383             ASServerSocket ss = (ASServerSocket) getServerSocket(serverPort);
384             ss.addClientSocketLocalPort(s.getLocalPort());
385         }
386     }
387
388     static boolean hasClientSocketLocalPorts(Socket JavaDoc s) {
389         ASServerSocket ss = (ASServerSocket) getServerSocket(s.getLocalPort());
390         return ss.hasClientSocketLocalPorts();
391     }
392
393     static boolean isLocalClient(Socket JavaDoc s) {
394         // Check if s is connected to a remote client (on a different machine)
395
InetAddress JavaDoc remoteAddr = s.getInetAddress();
396         return ( remoteAddr.equals(localHost)
397                  || remoteAddr.isSiteLocalAddress()
398              || remoteAddr.isLinkLocalAddress()
399              || remoteAddr.isLoopbackAddress()
400              || remoteAddr.isAnyLocalAddress());
401     }
402
403     static boolean isServerStartingUp() {
404         return peMain.isStartingUp();
405     }
406
407     static boolean isServerStartingUp(int port) {
408         if (isServerStartingUp() == true) {
409             return true;
410         }
411         if (port > 0 ) {
412             ASSocketService savedSS = ASSocketService.get(port);
413             if (savedSS != null) {
414                 return savedSS.entryBeingProcessed();
415             }
416         }
417         return false;
418     }
419
420     public static void triggerServerExit(){
421         synchronized (lock) {
422             triggered = true;
423             lock.notifyAll();
424         }
425     }
426
427     public static void waitForClientNotification(){
428         synchronized (lock) {
429             if (triggered == false) {
430                 try {
431                     lock.wait(TIMEOUT);
432                 } catch (Exception JavaDoc e ) {
433                     e.printStackTrace();
434                 }
435             }
436         }
437     }
438
439     /**
440      * If a client connects from within appserver and
441      * that triggers the service startup, that
442      * client should wait until service startup
443      * completes before being accepted by server.
444      *
445      * This method should be called, if and only if the
446      * connection is first ever connection to the server.
447      *
448      * @param s A connected socket from client.
449      */

450     public static void waitOnClientConnection(Socket JavaDoc s) {
451         int port = s.getPort();
452         ASSocketService ss = ASSocketService.get(port);
453         if (ss != null) {
454             ss._waitOnClientConnection();
455         }
456     }
457
458     void _waitOnClientConnection() {
459         if (entryBeingProcessed()) {
460             synchronized (acceptLock) {
461                 try {
462                     while (entryBeingProcessed()) {
463                         acceptLock.wait();
464                     }
465                 } catch (InterruptedException JavaDoc ie) {
466                 }
467             }
468         }
469     }
470
471     class EntryPointThread extends Thread JavaDoc {
472
473         private Selector JavaDoc selector = null;
474
475         EntryPointThread(Selector JavaDoc selector) {
476             this.selector = selector;
477         }
478
479         public void run() {
480
481             selectorblock:
482             while (true) {
483                 try {
484                     selector.select();
485                     Iterator JavaDoc it = selector.selectedKeys().iterator();
486                     while (it.hasNext()) {
487                         SelectionKey JavaDoc selKey = (SelectionKey JavaDoc)it.next();
488                         if (selKey.isValid() && selKey.isAcceptable()) {
489                             it.remove();
490                             // Service notified state will be set only by clients within
491
// JVM. If the service is notified by any client in the same
492
// JVM, then the selector is returned by a client from outside
493
// JVM. In this case, the service should start only after
494
// every startup operation completes.
495
if (state != SERVICENOTIFIED) {
496                                 if (peMain.isStartingUp()) {
497                                     synchronized (peMain) {
498                                         try {
499                                             while (peMain.isStartingUp()) {
500                                                 peMain.wait();
501                                             }
502                                         } catch (Exception JavaDoc e) {}
503                                     }
504                                 }
505                             }
506                             break selectorblock;
507                         }
508                     }
509
510                 } catch (Exception JavaDoc e) {
511                     if (logger.isLoggable(Level.FINEST)) {
512                         logger.log(Level.FINEST, e.getMessage(), e);
513                     }
514                     break;
515                     // The selector will be closed whenever actual server
516
// comes up. See removeListeningSelector() method.
517
// That can cause this exception. So, just return.
518
//return;
519
}
520             }
521
522
523             try {
524                 state = STARTING;
525                 generateEntryContext(new Integer JavaDoc(config.getPort()));
526                 state = STARTED;
527                 synchronized (acceptLock) {
528                     acceptLock.notifyAll();
529                 }
530             } catch (Exception JavaDoc e) {
531                 logger.log(Level.SEVERE, e.getMessage(), e);
532             }
533         }
534     }
535
536 }
537
Popular Tags