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.core.session;
21  
22  import java.io.IOException;
23  import java.net.SocketAddress;
24  import java.util.List;
25  import java.util.Set;
26  import java.util.concurrent.Executor;
27  
28  import org.apache.mina.core.file.FileRegion;
29  import org.apache.mina.core.filterchain.DefaultIoFilterChain;
30  import org.apache.mina.core.filterchain.IoFilter;
31  import org.apache.mina.core.filterchain.IoFilterChain;
32  import org.apache.mina.core.service.AbstractIoAcceptor;
33  import org.apache.mina.core.service.DefaultTransportMetadata;
34  import org.apache.mina.core.service.IoHandler;
35  import org.apache.mina.core.service.IoHandlerAdapter;
36  import org.apache.mina.core.service.IoProcessor;
37  import org.apache.mina.core.service.IoService;
38  import org.apache.mina.core.service.TransportMetadata;
39  import org.apache.mina.core.write.WriteRequest;
40  import org.apache.mina.core.write.WriteRequestQueue;
41  
42  /**
43   * A dummy {@link IoSession} for unit-testing or non-network-use of
44   * the classes that depends on {@link IoSession}.
45   *
46   * <h2>Overriding I/O request methods</h2>
47   * All I/O request methods (i.e. {@link #close()}, {@link #write(Object)}
48   * are final and therefore cannot be
49   * overridden, but you can always add your custom {@link IoFilter} to the
50   * {@link IoFilterChain} to intercept any I/O events and requests.
51   *
52   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
53   */
54  public class DummySession extends AbstractIoSession {
55  
56      private static final TransportMetadata TRANSPORT_METADATA = new DefaultTransportMetadata("mina", "dummy", false,
57              false, SocketAddress.class, IoSessionConfig.class, Object.class);
58  
59      private static final SocketAddress ANONYMOUS_ADDRESS = new SocketAddress() {
60          private static final long serialVersionUID = -496112902353454179L;
61  
62          @Override
63          public String toString() {
64              return "?";
65          }
66      };
67  
68      private volatile IoService service;
69  
70      private volatile IoSessionConfig config = new AbstractIoSessionConfig() {
71      };
72  
73      private final IoFilterChain filterChain = new DefaultIoFilterChain(this);
74  
75      private final IoProcessor<IoSession> processor;
76  
77      private volatile IoHandler handler = new IoHandlerAdapter();
78  
79      private volatile SocketAddress localAddress = ANONYMOUS_ADDRESS;
80  
81      private volatile SocketAddress remoteAddress = ANONYMOUS_ADDRESS;
82  
83      private volatile TransportMetadata transportMetadata = TRANSPORT_METADATA;
84  
85      /**
86       * Creates a new instance.
87       */
88      public DummySession() {
89          super(
90  
91          // Initialize dummy service.
92                  new AbstractIoAcceptor(new AbstractIoSessionConfig() {
93                  }, new Executor() {
94                      public void execute(Runnable command) {
95                          // Do nothing
96                      }
97                  }) {
98  
99                      @Override
100                     protected Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses)
101                             throws Exception {
102                         throw new UnsupportedOperationException();
103                     }
104 
105                     @Override
106                     protected void unbind0(List<? extends SocketAddress> localAddresses) throws Exception {
107                         throw new UnsupportedOperationException();
108                     }
109 
110                     public IoSession newSession(SocketAddress remoteAddress, SocketAddress localAddress) {
111                         throw new UnsupportedOperationException();
112                     }
113 
114                     public TransportMetadata getTransportMetadata() {
115                         return TRANSPORT_METADATA;
116                     }
117 
118                     @Override
119                     protected void dispose0() throws Exception {
120                     }
121                     
122                     /**
123                      * {@inheritDoc}
124                      */
125                     public IoSessionConfig getSessionConfig() {
126                         return sessionConfig;
127                     }
128                 });
129 
130         processor = new IoProcessor<IoSession>() {
131             public void add(IoSession session) {
132                 // Do nothing
133             }
134 
135             public void flush(IoSession session) {
136                 DummySession s = (DummySession) session;
137                 WriteRequest req = s.getWriteRequestQueue().poll(session);
138 
139                 // Chek that the request is not null. If the session has been closed,
140                 // we may not have any pending requests.
141                 if (req != null) {
142                     Object m = req.getMessage();
143                     if (m instanceof FileRegion) {
144                         FileRegion file = (FileRegion) m;
145                         try {
146                             file.getFileChannel().position(file.getPosition() + file.getRemainingBytes());
147                             file.update(file.getRemainingBytes());
148                         } catch (IOException e) {
149                             s.getFilterChain().fireExceptionCaught(e);
150                         }
151                     }
152                     getFilterChain().fireMessageSent(req);
153                 }
154             }
155 
156             /**
157              * {@inheritDoc}
158              */
159             public void write(IoSession session, WriteRequest writeRequest) {
160                 WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
161 
162                 writeRequestQueue.offer(session, writeRequest);
163 
164                 if (!session.isWriteSuspended()) {
165                     this.flush(session);
166                 }
167             }
168 
169             public void remove(IoSession session) {
170                 if (!session.getCloseFuture().isClosed()) {
171                     session.getFilterChain().fireSessionClosed();
172                 }
173             }
174 
175             public void updateTrafficControl(IoSession session) {
176                 // Do nothing
177             }
178 
179             public void dispose() {
180                 // Do nothing
181             }
182 
183             public boolean isDisposed() {
184                 return false;
185             }
186 
187             public boolean isDisposing() {
188                 return false;
189             }
190 
191         };
192 
193         this.service = super.getService();
194 
195         try {
196             IoSessionDataStructureFactory factory = new DefaultIoSessionDataStructureFactory();
197             setAttributeMap(factory.getAttributeMap(this));
198             setWriteRequestQueue(factory.getWriteRequestQueue(this));
199         } catch (Exception e) {
200             throw new InternalError();
201         }
202     }
203 
204     /**
205      * {@inheritDoc}
206      */
207     public IoSessionConfig getConfig() {
208         return config;
209     }
210 
211     /**
212      * Sets the configuration of this session.
213      * 
214      * @param config the {@link IoSessionConfig} to set
215      */
216     public void setConfig(IoSessionConfig config) {
217         if (config == null) {
218             throw new IllegalArgumentException("config");
219         }
220 
221         this.config = config;
222     }
223 
224     /**
225      * {@inheritDoc}
226      */
227     public IoFilterChain getFilterChain() {
228         return filterChain;
229     }
230 
231     /**
232      * {@inheritDoc}
233      */
234     public IoHandler getHandler() {
235         return handler;
236     }
237 
238     /**
239      * Sets the {@link IoHandler} which handles this session.
240      * 
241      * @param handler the {@link IoHandler} to set
242      */
243     public void setHandler(IoHandler handler) {
244         if (handler == null) {
245             throw new IllegalArgumentException("handler");
246         }
247 
248         this.handler = handler;
249     }
250 
251     /**
252      * {@inheritDoc}
253      */
254     public SocketAddress getLocalAddress() {
255         return localAddress;
256     }
257 
258     /**
259      * {@inheritDoc}
260      */
261     public SocketAddress getRemoteAddress() {
262         return remoteAddress;
263     }
264 
265     /**
266      * Sets the socket address of local machine which is associated with
267      * this session.
268      * 
269      * @param localAddress The socket address to set
270      */
271     public void setLocalAddress(SocketAddress localAddress) {
272         if (localAddress == null) {
273             throw new IllegalArgumentException("localAddress");
274         }
275 
276         this.localAddress = localAddress;
277     }
278 
279     /**
280      * Sets the socket address of remote peer.
281      * 
282      * @param remoteAddress The socket address to set
283      */
284     public void setRemoteAddress(SocketAddress remoteAddress) {
285         if (remoteAddress == null) {
286             throw new IllegalArgumentException("remoteAddress");
287         }
288 
289         this.remoteAddress = remoteAddress;
290     }
291 
292     /**
293      * {@inheritDoc}
294      */
295     public IoService getService() {
296         return service;
297     }
298 
299     /**
300      * Sets the {@link IoService} which provides I/O service to this session.
301      * 
302      * @param service The {@link IoService} to set
303      */
304     public void setService(IoService service) {
305         if (service == null) {
306             throw new IllegalArgumentException("service");
307         }
308 
309         this.service = service;
310     }
311 
312     /**
313      * {@inheritDoc}
314      */
315     @Override
316     public final IoProcessor<IoSession> getProcessor() {
317         return processor;
318     }
319 
320     /**
321      * {@inheritDoc}
322      */
323     public TransportMetadata getTransportMetadata() {
324         return transportMetadata;
325     }
326 
327     /**
328      * Sets the {@link TransportMetadata} that this session runs on.
329      * 
330      * @param transportMetadata The {@link TransportMetadata} to set
331      */
332     public void setTransportMetadata(TransportMetadata transportMetadata) {
333         if (transportMetadata == null) {
334             throw new IllegalArgumentException("transportMetadata");
335         }
336 
337         this.transportMetadata = transportMetadata;
338     }
339 
340     /**
341      * {@inheritDoc}
342      */
343     @Override
344     public void setScheduledWriteBytes(int byteCount) {
345         super.setScheduledWriteBytes(byteCount);
346     }
347 
348     /**
349      * {@inheritDoc}
350      */
351     @Override
352     public void setScheduledWriteMessages(int messages) {
353         super.setScheduledWriteMessages(messages);
354     }
355 
356     /**
357      * Update all statistical properties related with throughput.  By default
358      * this method returns silently without updating the throughput properties
359      * if they were calculated already within last
360      * {@link IoSessionConfig#getThroughputCalculationInterval() calculation interval}.
361      * If, however, <tt>force</tt> is specified as <tt>true</tt>, this method
362      * updates the throughput properties immediately.
363      * 
364      * @param force the flag that forces the update of properties immediately if <tt>true</tt>
365      */
366     public void updateThroughput(boolean force) {
367         super.updateThroughput(System.currentTimeMillis(), force);
368     }
369 }