KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > mina > handler > demux > DemuxingIoHandler


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.handler.demux;
21
22 import java.util.Collections JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.concurrent.ConcurrentHashMap JavaDoc;
26
27 import org.apache.mina.common.IoHandler;
28 import org.apache.mina.common.IoHandlerAdapter;
29 import org.apache.mina.common.IoSession;
30 import org.apache.mina.util.IdentityHashSet;
31
32 /**
33  * A {@link IoHandler} that demuxes <code>messageReceived</code> events
34  * to the appropriate {@link MessageHandler}.
35  * <p>
36  * You can freely register and deregister {@link MessageHandler}s using
37  * {@link #addMessageHandler(Class, MessageHandler)} and
38  * {@link #removeMessageHandler(Class)}.
39  * </p>
40  * <p>
41  * When <code>message</code> is received through a call to
42  * {@link #messageReceived(IoSession, Object)} the class of the
43  * <code>message</code> object will be used to find a {@link MessageHandler} for
44  * that particular message type. If no {@link MessageHandler} instance can be
45  * found for the immediate class (i.e. <code>message.getClass()</code>) the
46  * interfaces implemented by the immediate class will be searched in depth-first
47  * order. If no match can be found for any of the interfaces the search will be
48  * repeated recursively for the superclass of the immediate class
49  * (i.e. <code>message.getClass().getSuperclass()</code>).
50  * </p>
51  * <p>
52  * Consider the following type hierarchy (<code>Cx</code> are classes while
53  * <code>Ix</code> are interfaces):
54  * <pre>
55  * C3 - I7 - I9
56  * | | /\
57  * | I8 I3 I4
58  * |
59  * C2 - I5 - I6
60  * |
61  * C1 - I1 - I2 - I4
62  * | |
63  * | I3
64  * Object
65  * </pre>
66  * When <code>message</code> is of type <code>C3</code> this hierarchy will be
67  * searched in the following order:
68  * <code>C3, I7, I8, I9, I3, I4, C2, I5, I6, C1, I1, I2, I3, I4, Object</code>.
69  * </p>
70  * <p>
71  * For efficiency searches will be cached. Calls to
72  * {@link #addMessageHandler(Class, MessageHandler)} and
73  * {@link #removeMessageHandler(Class)} clear this cache.
74  * </p>
75  *
76  * @author The Apache Directory Project (mina-dev@directory.apache.org)
77  * @version $Rev: 555855 $, $Date: 2007-07-13 12:19:00 +0900 (금, 13 7월 2007) $
78  */

79 public class DemuxingIoHandler extends IoHandlerAdapter {
80     private final Map JavaDoc<Class JavaDoc, MessageHandler> findHandlerCache = new ConcurrentHashMap JavaDoc<Class JavaDoc, MessageHandler>();
81
82     private final Map JavaDoc<Class JavaDoc, MessageHandler> type2handler = new ConcurrentHashMap JavaDoc<Class JavaDoc, MessageHandler>();
83
84     /**
85      * Creates a new instance with no registered {@link MessageHandler}s.
86      */

87     public DemuxingIoHandler() {
88     }
89
90     /**
91      * Registers a {@link MessageHandler} that receives the messages of
92      * the specified <code>type</code>.
93      *
94      * @return the old handler if there is already a registered handler for
95      * the specified <tt>type</tt>. <tt>null</tt> otherwise.
96      */

97     @SuppressWarnings JavaDoc("unchecked")
98     public <E> MessageHandler<? super E> addMessageHandler(Class JavaDoc<E> type,
99             MessageHandler<? super E> handler) {
100         findHandlerCache.clear();
101         return type2handler.put(type, handler);
102     }
103
104     /**
105      * Deregisters a {@link MessageHandler} that receives the messages of
106      * the specified <code>type</code>.
107      *
108      * @return the removed handler if successfully removed. <tt>null</tt> otherwise.
109      */

110     @SuppressWarnings JavaDoc("unchecked")
111     public <E> MessageHandler<? super E> removeMessageHandler(Class JavaDoc<E> type) {
112         findHandlerCache.clear();
113         return type2handler.remove(type);
114     }
115
116     /**
117      * Returns the {@link MessageHandler} which is registered to process
118      * the specified <code>type</code>.
119      */

120     @SuppressWarnings JavaDoc("unchecked")
121     public <E> MessageHandler<? super E> getMessageHandler(Class JavaDoc<E> type) {
122         return type2handler.get(type);
123     }
124
125     /**
126      * Returns the {@link Map} which contains all messageType-{@link MessageHandler}
127      * pairs registered to this handler.
128      */

129     public Map JavaDoc<Class JavaDoc, MessageHandler> getMessageHandlerMap() {
130         return Collections.unmodifiableMap(type2handler);
131     }
132
133     /**
134      * Forwards the received events into the appropriate {@link MessageHandler}
135      * which is registered by {@link #addMessageHandler(Class, MessageHandler)}.
136      */

137     public void messageReceived(IoSession session, Object JavaDoc message)
138             throws Exception JavaDoc {
139         MessageHandler<Object JavaDoc> handler = findHandler(message.getClass());
140         if (handler != null) {
141             handler.messageReceived(session, message);
142         } else {
143             throw new UnknownMessageTypeException(
144                     "No message handler found for message: " + message);
145         }
146     }
147
148     protected MessageHandler<Object JavaDoc> findHandler(Class JavaDoc type) {
149         return findHandler(type, null);
150     }
151
152     @SuppressWarnings JavaDoc("unchecked")
153     private MessageHandler<Object JavaDoc> findHandler(Class JavaDoc type,
154             Set JavaDoc<Class JavaDoc> triedClasses) {
155         MessageHandler handler = null;
156
157         if (triedClasses != null && triedClasses.contains(type))
158             return null;
159
160         /*
161          * Try the cache first.
162          */

163         handler = findHandlerCache.get(type);
164         if (handler != null)
165             return handler;
166
167         /*
168          * Try the registered handlers for an immediate match.
169          */

170         handler = type2handler.get(type);
171
172         if (handler == null) {
173             /*
174              * No immediate match could be found. Search the type's interfaces.
175              */

176
177             if (triedClasses == null)
178                 triedClasses = new IdentityHashSet<Class JavaDoc>();
179             triedClasses.add(type);
180
181             Class JavaDoc[] interfaces = type.getInterfaces();
182             for (int i = 0; i < interfaces.length; i++) {
183                 handler = findHandler(interfaces[i], triedClasses);
184                 if (handler != null)
185                     break;
186             }
187         }
188
189         if (handler == null) {
190             /*
191              * No match in type's interfaces could be found. Search the
192              * superclass.
193              */

194
195             Class JavaDoc superclass = type.getSuperclass();
196             if (superclass != null)
197                 handler = findHandler(superclass);
198         }
199
200         /*
201          * Make sure the handler is added to the cache. By updating the cache
202          * here all the types (superclasses and interfaces) in the path which
203          * led to a match will be cached along with the immediate message type.
204          */

205         if (handler != null)
206             findHandlerCache.put(type, handler);
207
208         return handler;
209     }
210 }
211
Popular Tags