IoServiceListenerSupport.java
001 /*
002  *  Licensed to the Apache Software Foundation (ASF) under one
003  *  or more contributor license agreements.  See the NOTICE file
004  *  distributed with this work for additional information
005  *  regarding copyright ownership.  The ASF licenses this file
006  *  to you under the Apache License, Version 2.0 (the
007  *  "License"); you may not use this file except in compliance
008  *  with the License.  You may obtain a copy of the License at
009  *  
010  *    http://www.apache.org/licenses/LICENSE-2.0
011  *  
012  *  Unless required by applicable law or agreed to in writing,
013  *  software distributed under the License is distributed on an
014  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015  *  KIND, either express or implied.  See the License for the
016  *  specific language governing permissions and limitations
017  *  under the License. 
018  *  
019  */
020 package org.apache.mina.common.support;
021 
022 import java.net.SocketAddress;
023 import java.util.ArrayList;
024 import java.util.Collections;
025 import java.util.HashMap;
026 import java.util.HashSet;
027 import java.util.Iterator;
028 import java.util.List;
029 import java.util.Map;
030 import java.util.Set;
031 import java.util.concurrent.CountDownLatch;
032 
033 import org.apache.mina.common.IoAcceptorConfig;
034 import org.apache.mina.common.IoConnector;
035 import org.apache.mina.common.IoFuture;
036 import org.apache.mina.common.IoFutureListener;
037 import org.apache.mina.common.IoHandler;
038 import org.apache.mina.common.IoService;
039 import org.apache.mina.common.IoServiceConfig;
040 import org.apache.mina.common.IoServiceListener;
041 import org.apache.mina.common.IoSession;
042 import org.apache.mina.util.IdentityHashSet;
043 
044 /**
045  * A helper which provides addition and removal of {@link IoServiceListener}s and firing
046  * events.
047  
048  @author The Apache Directory Project (mina-dev@directory.apache.org)
049  @version $Rev: 446526 $, $Date: 2006-09-15 01:44:11 -0400 (Fri, 15 Sep 2006) $
050  */
051 public class IoServiceListenerSupport
052 {
053     /**
054      * A list of {@link IoServiceListener}s.
055      */
056     private final List listeners = new ArrayList();
057 
058     /**
059      * Tracks managed <tt>serviceAddress</tt>es.
060      */
061     private final Set managedServiceAddresses = new HashSet();
062     
063     /**
064      * Tracks managed sesssions with <tt>serviceAddress</tt> as a key.
065      */
066     private final Map managedSessions = new HashMap();
067     
068     /**
069      * Creates a new instance.
070      */
071     public IoServiceListenerSupport()
072     {
073     }
074     
075     /**
076      * Adds a new listener.
077      */
078     public void addIoServiceListener listener )
079     {
080         synchronizedlisteners )
081         {
082             listeners.addlistener );
083         }
084     }
085 
086     /**
087      * Removes an existing listener.
088      */
089     public void removeIoServiceListener listener )
090     {
091         synchronizedlisteners )
092         {
093             listeners.removelistener );
094         }
095     }
096     
097     public Set getManagedServiceAddresses()
098     {
099         return Collections.unmodifiableSetmanagedServiceAddresses );
100     }
101 
102     public boolean isManagedSocketAddress serviceAddress )
103     {
104         synchronizedmanagedServiceAddresses )
105         {
106             return managedServiceAddresses.containsserviceAddress );
107         }
108     }
109 
110     public Set getManagedSessionsSocketAddress serviceAddress )
111     {
112         Set sessions;
113         synchronizedmanagedSessions )
114         {
115             sessions = Set managedSessions.getserviceAddress );
116             ifsessions == null )
117             {
118                 sessions = new IdentityHashSet();
119             }
120         }
121         
122         synchronizedsessions )
123         {
124             return new IdentityHashSetsessions );
125         }
126     }
127 
128     /**
129      * Calls {@link IoServiceListener#serviceActivated(IoService, SocketAddress, IoHandler, IoServiceConfig)}
130      * for all registered listeners.
131      */
132     public void fireServiceActivated(
133             IoService service, SocketAddress serviceAddress,
134             IoHandler handler, IoServiceConfig config )
135     {
136         synchronizedmanagedServiceAddresses )
137         {
138             if!managedServiceAddresses.addserviceAddress ) )
139             {
140                 return;
141             }
142         }
143 
144         synchronizedlisteners )
145         {
146             forIterator i = listeners.iterator(); i.hasNext())
147             {
148                 ( ( IoServiceListener i.next() ).serviceActivated(
149                         service, serviceAddress, handler, config );
150             }
151         }
152     }
153     
154     /**
155      * Calls {@link IoServiceListener#serviceDeactivated(IoService, SocketAddress, IoHandler, IoServiceConfig)}
156      * for all registered listeners.
157      */
158     public synchronized void fireServiceDeactivated(
159             IoService service, SocketAddress serviceAddress,
160             IoHandler handler, IoServiceConfig config )
161     {
162         synchronizedmanagedServiceAddresses )
163         {
164             if!managedServiceAddresses.removeserviceAddress ) )
165             {
166                 return;
167             }
168         }
169         
170         try
171         {
172             synchronizedlisteners )
173             {
174                 forIterator i = listeners.iterator(); i.hasNext())
175                 {
176                     ( ( IoServiceListener i.next() ).serviceDeactivated(
177                             service, serviceAddress, handler, config );
178                 }
179             }
180         }
181         finally
182         {
183             disconnectSessionsserviceAddress, config );
184         }
185     }
186     
187     
188     /**
189      * Calls {@link IoServiceListener#sessionCreated(IoSession)} for all registered listeners.
190      */
191     public void fireSessionCreatedIoSession session )
192     {
193         SocketAddress serviceAddress = session.getServiceAddress();
194         
195         // Get the session set.
196         boolean firstSession = false;
197         Set sessions;
198         synchronizedmanagedSessions )
199         {
200             sessions = Set managedSessions.getserviceAddress );
201             ifsessions == null )
202             {
203                 sessions = new IdentityHashSet();
204                 managedSessions.putserviceAddress, sessions );
205                 firstSession = true;
206             }
207         }
208         
209         // If already registered, ignore.
210         synchronizedsessions )
211         {
212             if !sessions.addsession ) )
213             {
214                 return;
215             }
216         }
217         
218         // If the first connector session, fire a virtual service activation event.
219         ifsession.getService() instanceof IoConnector && firstSession )
220         {
221             fireServiceActivated(
222                     session.getService(), session.getServiceAddress(),
223                     session.getHandler(), session.getServiceConfig() );
224         }
225 
226         // Fire session events.
227         session.getFilterChain().fireSessionCreatedsession );
228         session.getFilterChain().fireSessionOpenedsession);
229         
230         // Fire listener events.
231         synchronizedlisteners )
232         {
233             forIterator i = listeners.iterator(); i.hasNext())
234             {
235                 ( ( IoServiceListener i.next() ).sessionCreatedsession );
236             }
237         }
238     }
239     
240     /**
241      * Calls {@link IoServiceListener#sessionDestroyed(IoSession)} for all registered listeners.
242      */
243     public void fireSessionDestroyedIoSession session )
244     {
245         SocketAddress serviceAddress = session.getServiceAddress();
246         
247         // Get the session set.
248         Set sessions;
249         boolean lastSession = false;
250         synchronizedmanagedSessions )
251         {
252             sessions = Set managedSessions.getserviceAddress );
253             // Ignore if unknown.
254             ifsessions == null )
255             {
256                 return;
257             }
258             
259             // Try to remove the remaining empty seession set after removal.
260             synchronizedsessions )
261             {
262                 sessions.removesession );
263                 ifsessions.isEmpty() )
264                 {
265                     managedSessions.removeserviceAddress );
266                     lastSession = true;
267                 }
268             }
269         }
270         
271         // Fire session events.
272         session.getFilterChain().fireSessionClosedsession );
273         
274         // Fire listener events.
275         try
276         {
277             synchronizedlisteners )
278             {
279                 forIterator i = listeners.iterator(); i.hasNext())
280                 {
281                     ( ( IoServiceListener i.next() ).sessionDestroyedsession );
282                 }
283             }
284         }
285         finally
286         {
287             // Fire a virtual service deactivation event for the last session of the connector.
288             //TODO double-check that this is *STILL* the last session. May not be the case
289             ifsession.getService() instanceof IoConnector && lastSession )
290             {
291                 fireServiceDeactivated(
292                         session.getService(), session.getServiceAddress(),
293                         session.getHandler(), session.getServiceConfig() );
294             }
295         }
296     }
297 
298     private void disconnectSessionsSocketAddress serviceAddress, IoServiceConfig config )
299     {
300         if!config instanceof IoAcceptorConfig ) )
301         {
302             return;
303         }
304 
305         if!( ( IoAcceptorConfig config ).isDisconnectOnUnbind() )
306         {
307             return;
308         }
309 
310         Set sessions;
311         synchronizedmanagedSessions )
312         {
313             sessions = Set managedSessions.getserviceAddress );
314         }
315         
316         ifsessions == null )
317         {
318             return;
319         }
320 
321         Set sessionsCopy;
322         
323         // Create a copy to avoid ConcurrentModificationException
324         synchronizedsessions )
325         {
326             sessionsCopy = new IdentityHashSetsessions );
327         }
328 
329         final CountDownLatch latch = new CountDownLatch(sessionsCopy.size());
330 
331         forIterator i = sessionsCopy.iterator(); i.hasNext())
332         {
333             ( ( IoSession i.next() ).close().addListenernew IoFutureListener()
334             {
335                 public void operationCompleteIoFuture future )
336                 {
337                     latch.countDown();
338                 }
339             } );
340         }
341 
342         try
343         {
344             latch.await();
345         }
346         catchInterruptedException ie )
347         {
348             // Ignored
349         }
350     }
351 }