View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.common;
21  
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Set;
25  import java.util.concurrent.CopyOnWriteArrayList;
26  import java.util.concurrent.atomic.AtomicBoolean;
27  
28  import org.apache.mina.util.ConcurrentHashSet;
29  
30  /**
31   * A helper which provides addition and removal of {@link IoServiceListener}s and firing
32   * events.
33   *
34   * @author The Apache MINA Project (dev@mina.apache.org)
35   * @version $Rev: 600807 $, $Date: 2007-12-03 23:56:50 -0700 (Mon, 03 Dec 2007) $
36   */
37  public class IoServiceListenerSupport {
38      /**
39       * The {@link IoService} that this instance manages.
40       */
41      private final IoService service;
42  
43      /**
44       * A list of {@link IoServiceListener}s.
45       */
46      private final List<IoServiceListener> listeners = new CopyOnWriteArrayList<IoServiceListener>();
47  
48      /**
49       * Tracks managed sessions.
50       */
51      private final Set<IoSession> managedSessions = new ConcurrentHashSet<IoSession>();
52  
53      /**
54       * Read only version of {@link #managedSessions}.
55       */
56      private final Set<IoSession> readOnlyManagedSessions = Collections.unmodifiableSet(managedSessions);
57      
58      private final AtomicBoolean activated = new AtomicBoolean();
59      private volatile long activationTime;
60      private volatile int largestManagedSessionCount;
61      private volatile long cumulativeManagedSessionCount;
62  
63      /**
64       * Creates a new instance.
65       */
66      public IoServiceListenerSupport(IoService service) {
67          if (service == null) {
68              throw new NullPointerException("service");
69          }
70          this.service = service;
71      }
72  
73      /**
74       * Adds a new listener.
75       */
76      public void add(IoServiceListener listener) {
77          listeners.add(listener);
78      }
79  
80      /**
81       * Removes an existing listener.
82       */
83      public void remove(IoServiceListener listener) {
84          listeners.remove(listener);
85      }
86      
87      public long getActivationTime() {
88          return activationTime;
89      }
90  
91      public Set<IoSession> getManagedSessions() {
92          return readOnlyManagedSessions;
93      }
94      
95      public int getManagedSessionCount() {
96          return managedSessions.size();
97      }
98      
99      public int getLargestManagedSessionCount() {
100         return largestManagedSessionCount;
101     }
102     
103     public long getCumulativeManagedSessionCount() {
104         return cumulativeManagedSessionCount;
105     }
106 
107     public boolean isActive() {
108         return activated.get();
109     }
110 
111     /**
112      * Calls {@link IoServiceListener#serviceActivated(IoService)}
113      * for all registered listeners.
114      */
115     public void fireServiceActivated() {
116         if (!activated.compareAndSet(false, true)) {
117             return;
118         }
119 
120         activationTime = System.currentTimeMillis();
121 
122         for (IoServiceListener l : listeners) {
123             l.serviceActivated(service);
124         }
125     }
126     
127     /**
128      * Calls {@link IoServiceListener#serviceIdle(IoService, IdleStatus)}
129      * for all registered listeners.
130      */
131     public void fireServiceIdle(IdleStatus status) {
132         if (!activated.get()) {
133             return;
134         }
135 
136         for (IoServiceListener l : listeners) {
137             l.serviceIdle(service, status);
138         }
139     }
140 
141 
142     /**
143      * Calls {@link IoServiceListener#serviceDeactivated(IoService)}
144      * for all registered listeners.
145      */
146     public void fireServiceDeactivated() {
147         if (!activated.compareAndSet(true, false)) {
148             return;
149         }
150 
151         try {
152             for (IoServiceListener l : listeners) {
153                 l.serviceDeactivated(service);
154             }
155         } finally {
156             disconnectSessions();
157         }
158     }
159 
160     /**
161      * Calls {@link IoServiceListener#sessionCreated(IoSession)} for all registered listeners.
162      */
163     public void fireSessionCreated(IoSession session) {
164         boolean firstSession = false;
165         if (session.getService() instanceof IoConnector) {
166             synchronized (managedSessions) {
167                 firstSession = managedSessions.isEmpty();
168             }
169         }
170 
171         // If already registered, ignore.
172         if (!managedSessions.add(session)) {
173             return;
174         }
175         
176         // If the first connector session, fire a virtual service activation event.
177         if (firstSession) {
178             fireServiceActivated();
179         }
180 
181         // Fire session events.
182         session.getFilterChain().fireSessionCreated();
183         session.getFilterChain().fireSessionOpened();
184 
185         int managedSessionCount = managedSessions.size();
186         if (managedSessionCount > largestManagedSessionCount) {
187             largestManagedSessionCount = managedSessionCount;
188         }
189         cumulativeManagedSessionCount ++;
190 
191         // Fire listener events.
192         for (IoServiceListener l : listeners) {
193             l.sessionCreated(session);
194         }
195     }
196 
197     /**
198      * Calls {@link IoServiceListener#sessionDestroyed(IoSession)} for all registered listeners.
199      */
200     public void fireSessionDestroyed(IoSession session) {
201         // Try to remove the remaining empty session set after removal.
202         if (!managedSessions.remove(session)) {
203             return;
204         }
205 
206         // Fire session events.
207         session.getFilterChain().fireSessionClosed();
208 
209         // Fire listener events.
210         try {
211             for (IoServiceListener l : listeners) {
212                 l.sessionDestroyed(session);
213             }
214         } finally {
215             // Fire a virtual service deactivation event for the last session of the connector.
216             if (session.getService() instanceof IoConnector) {
217                 boolean lastSession = false;
218                 synchronized (managedSessions) {
219                     lastSession = managedSessions.isEmpty();
220                 }
221                 if (lastSession) {
222                     fireServiceDeactivated();
223                 }
224             }
225         }
226     }
227 
228     private void disconnectSessions() {
229         if (!(service instanceof IoAcceptor)) {
230             return;
231         }
232 
233         if (!((IoAcceptor) service).isCloseOnDeactivation()) {
234             return;
235         }
236 
237         Object lock = new Object();
238         IoFutureListener<IoFuture> listener = new LockNotifyingListener(lock);
239 
240         for (IoSession s : managedSessions) {
241             s.close().addListener(listener);
242         }
243 
244         try {
245             synchronized (lock) {
246                 while (!managedSessions.isEmpty()) {
247                     lock.wait(500);
248                 }
249             }
250         } catch (InterruptedException ie) {
251             // Ignored
252         }
253     }
254 
255     private static class LockNotifyingListener implements IoFutureListener<IoFuture> {
256         private final Object lock;
257 
258         public LockNotifyingListener(Object lock) {
259             this.lock = lock;
260         }
261 
262         public void operationComplete(IoFuture future) {
263             synchronized (lock) {
264                 lock.notifyAll();
265             }
266         }
267     }
268 }