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;
021:
022: import java.util.Collections;
023: import java.util.List;
024: import java.util.Set;
025: import java.util.concurrent.CopyOnWriteArrayList;
026: import java.util.concurrent.atomic.AtomicBoolean;
027:
028: import org.apache.mina.util.ConcurrentHashSet;
029:
030: /**
031: * A helper which provides addition and removal of {@link IoServiceListener}s and firing
032: * events.
033: *
034: * @author The Apache MINA Project (dev@mina.apache.org)
035: * @version $Rev: 600807 $, $Date: 2007-12-03 23:56:50 -0700 (Mon, 03 Dec 2007) $
036: */
037: public class IoServiceListenerSupport {
038: /**
039: * The {@link IoService} that this instance manages.
040: */
041: private final IoService service;
042:
043: /**
044: * A list of {@link IoServiceListener}s.
045: */
046: private final List<IoServiceListener> listeners = new CopyOnWriteArrayList<IoServiceListener>();
047:
048: /**
049: * Tracks managed sessions.
050: */
051: private final Set<IoSession> managedSessions = new ConcurrentHashSet<IoSession>();
052:
053: /**
054: * Read only version of {@link #managedSessions}.
055: */
056: private final Set<IoSession> readOnlyManagedSessions = Collections
057: .unmodifiableSet(managedSessions);
058:
059: private final AtomicBoolean activated = new AtomicBoolean();
060: private volatile long activationTime;
061: private volatile int largestManagedSessionCount;
062: private volatile long cumulativeManagedSessionCount;
063:
064: /**
065: * Creates a new instance.
066: */
067: public IoServiceListenerSupport(IoService service) {
068: if (service == null) {
069: throw new NullPointerException("service");
070: }
071: this .service = service;
072: }
073:
074: /**
075: * Adds a new listener.
076: */
077: public void add(IoServiceListener listener) {
078: listeners.add(listener);
079: }
080:
081: /**
082: * Removes an existing listener.
083: */
084: public void remove(IoServiceListener listener) {
085: listeners.remove(listener);
086: }
087:
088: public long getActivationTime() {
089: return activationTime;
090: }
091:
092: public Set<IoSession> getManagedSessions() {
093: return readOnlyManagedSessions;
094: }
095:
096: public int getManagedSessionCount() {
097: return managedSessions.size();
098: }
099:
100: public int getLargestManagedSessionCount() {
101: return largestManagedSessionCount;
102: }
103:
104: public long getCumulativeManagedSessionCount() {
105: return cumulativeManagedSessionCount;
106: }
107:
108: public boolean isActive() {
109: return activated.get();
110: }
111:
112: /**
113: * Calls {@link IoServiceListener#serviceActivated(IoService)}
114: * for all registered listeners.
115: */
116: public void fireServiceActivated() {
117: if (!activated.compareAndSet(false, true)) {
118: return;
119: }
120:
121: activationTime = System.currentTimeMillis();
122:
123: for (IoServiceListener l : listeners) {
124: l.serviceActivated(service);
125: }
126: }
127:
128: /**
129: * Calls {@link IoServiceListener#serviceIdle(IoService, IdleStatus)}
130: * for all registered listeners.
131: */
132: public void fireServiceIdle(IdleStatus status) {
133: if (!activated.get()) {
134: return;
135: }
136:
137: for (IoServiceListener l : listeners) {
138: l.serviceIdle(service, status);
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(
239: lock);
240:
241: for (IoSession s : managedSessions) {
242: s.close().addListener(listener);
243: }
244:
245: try {
246: synchronized (lock) {
247: while (!managedSessions.isEmpty()) {
248: lock.wait(500);
249: }
250: }
251: } catch (InterruptedException ie) {
252: // Ignored
253: }
254: }
255:
256: private static class LockNotifyingListener implements
257: IoFutureListener<IoFuture> {
258: private final Object lock;
259:
260: public LockNotifyingListener(Object lock) {
261: this .lock = lock;
262: }
263:
264: public void operationComplete(IoFuture future) {
265: synchronized (lock) {
266: lock.notifyAll();
267: }
268: }
269: }
270: }
|