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                      @Override
95                      public void execute(Runnable command) {
96                          // Do nothing
97                      }
98                  }) {
99                      /**
100                      * {@inheritDoc}
101                      */
102                     @Override
103                     protected Set<SocketAddress> bindInternal(List<? extends SocketAddress> localAddresses)
104                             throws Exception {
105                         throw new UnsupportedOperationException();
106                     }
107 
108                     /**
109                      * {@inheritDoc}
110                      */
111                     @Override
112                     protected void unbind0(List<? extends SocketAddress> localAddresses) throws Exception {
113                         throw new UnsupportedOperationException();
114                     }
115 
116                     /**
117                      * {@inheritDoc}
118                      */
119                     @Override
120                     public IoSession newSession(SocketAddress remoteAddress, SocketAddress localAddress) {
121                         throw new UnsupportedOperationException();
122                     }
123 
124                     /**
125                      * {@inheritDoc}
126                      */
127                     @Override
128                     public TransportMetadata getTransportMetadata() {
129                         return TRANSPORT_METADATA;
130                     }
131 
132                     /**
133                      * {@inheritDoc}
134                      */
135                     @Override
136                     protected void dispose0() throws Exception {
137                     }
138                     
139                     /**
140                      * {@inheritDoc}
141                      */
142                     @Override
143                     public IoSessionConfig getSessionConfig() {
144                         return sessionConfig;
145                     }
146                 });
147 
148         processor = new IoProcessor<IoSession>() {
149             /**
150              * {@inheritDoc}
151              */
152             @Override
153             public void add(IoSession session) {
154                 // Do nothing
155             }
156 
157             /**
158              * {@inheritDoc}
159              */
160             @Override
161             public void flush(IoSession session) {
162                 DummySession s = (DummySession) session;
163                 WriteRequest req = s.getWriteRequestQueue().poll(session);
164 
165                 // Chek that the request is not null. If the session has been closed,
166                 // we may not have any pending requests.
167                 if (req != null) {
168                     Object m = req.getMessage();
169                     if (m instanceof FileRegion) {
170                         FileRegion file = (FileRegion) m;
171                         try {
172                             file.getFileChannel().position(file.getPosition() + file.getRemainingBytes());
173                             file.update(file.getRemainingBytes());
174                         } catch (IOException e) {
175                             s.getFilterChain().fireExceptionCaught(e);
176                         }
177                     }
178                     getFilterChain().fireMessageSent(req);
179                 }
180             }
181 
182             /**
183              * {@inheritDoc}
184              */
185             @Override
186             public void write(IoSession session, WriteRequest writeRequest) {
187                 WriteRequestQueue writeRequestQueue = session.getWriteRequestQueue();
188 
189                 writeRequestQueue.offer(session, writeRequest);
190 
191                 if (!session.isWriteSuspended()) {
192                     this.flush(session);
193                 }
194             }
195 
196             /**
197              * {@inheritDoc}
198              */
199             @Override
200             public void remove(IoSession session) {
201                 if (!session.getCloseFuture().isClosed()) {
202                     session.getFilterChain().fireSessionClosed();
203                 }
204             }
205 
206             /**
207              * {@inheritDoc}
208              */
209             @Override
210             public void updateTrafficControl(IoSession session) {
211                 // Do nothing
212             }
213 
214             /**
215              * {@inheritDoc}
216              */
217             @Override
218             public void dispose() {
219                 // Do nothing
220             }
221 
222             /**
223              * {@inheritDoc}
224              */
225             @Override
226             public boolean isDisposed() {
227                 return false;
228             }
229 
230             /**
231              * {@inheritDoc}
232              */
233             @Override
234             public boolean isDisposing() {
235                 return false;
236             }
237 
238         };
239 
240         this.service = super.getService();
241 
242         try {
243             IoSessionDataStructureFactory factory = new DefaultIoSessionDataStructureFactory();
244             setAttributeMap(factory.getAttributeMap(this));
245             setWriteRequestQueue(factory.getWriteRequestQueue(this));
246         } catch (Exception e) {
247             throw new InternalError();
248         }
249     }
250 
251     /**
252      * {@inheritDoc}
253      */
254     @Override
255     public IoSessionConfig getConfig() {
256         return config;
257     }
258 
259     /**
260      * Sets the configuration of this session.
261      * 
262      * @param config the {@link IoSessionConfig} to set
263      */
264     public void setConfig(IoSessionConfig config) {
265         if (config == null) {
266             throw new IllegalArgumentException("config");
267         }
268 
269         this.config = config;
270     }
271 
272     /**
273      * {@inheritDoc}
274      */
275     @Override
276     public IoFilterChain getFilterChain() {
277         return filterChain;
278     }
279 
280     /**
281      * {@inheritDoc}
282      */
283     @Override
284     public IoHandler getHandler() {
285         return handler;
286     }
287 
288     /**
289      * Sets the {@link IoHandler} which handles this session.
290      * 
291      * @param handler the {@link IoHandler} to set
292      */
293     public void setHandler(IoHandler handler) {
294         if (handler == null) {
295             throw new IllegalArgumentException("handler");
296         }
297 
298         this.handler = handler;
299     }
300 
301     /**
302      * {@inheritDoc}
303      */
304     @Override
305     public SocketAddress getLocalAddress() {
306         return localAddress;
307     }
308 
309     /**
310      * {@inheritDoc}
311      */
312     @Override
313     public SocketAddress getRemoteAddress() {
314         return remoteAddress;
315     }
316 
317     /**
318      * Sets the socket address of local machine which is associated with
319      * this session.
320      * 
321      * @param localAddress The socket address to set
322      */
323     public void setLocalAddress(SocketAddress localAddress) {
324         if (localAddress == null) {
325             throw new IllegalArgumentException("localAddress");
326         }
327 
328         this.localAddress = localAddress;
329     }
330 
331     /**
332      * Sets the socket address of remote peer.
333      * 
334      * @param remoteAddress The socket address to set
335      */
336     public void setRemoteAddress(SocketAddress remoteAddress) {
337         if (remoteAddress == null) {
338             throw new IllegalArgumentException("remoteAddress");
339         }
340 
341         this.remoteAddress = remoteAddress;
342     }
343 
344     /**
345      * {@inheritDoc}
346      */
347     @Override
348     public IoService getService() {
349         return service;
350     }
351 
352     /**
353      * Sets the {@link IoService} which provides I/O service to this session.
354      * 
355      * @param service The {@link IoService} to set
356      */
357     public void setService(IoService service) {
358         if (service == null) {
359             throw new IllegalArgumentException("service");
360         }
361 
362         this.service = service;
363     }
364 
365     /**
366      * {@inheritDoc}
367      */
368     @Override
369     public final IoProcessor<IoSession> getProcessor() {
370         return processor;
371     }
372 
373     /**
374      * {@inheritDoc}
375      */
376     @Override
377     public TransportMetadata getTransportMetadata() {
378         return transportMetadata;
379     }
380 
381     /**
382      * Sets the {@link TransportMetadata} that this session runs on.
383      * 
384      * @param transportMetadata The {@link TransportMetadata} to set
385      */
386     public void setTransportMetadata(TransportMetadata transportMetadata) {
387         if (transportMetadata == null) {
388             throw new IllegalArgumentException("transportMetadata");
389         }
390 
391         this.transportMetadata = transportMetadata;
392     }
393 
394     /**
395      * {@inheritDoc}
396      */
397     @Override
398     public void setScheduledWriteBytes(int byteCount) {
399         super.setScheduledWriteBytes(byteCount);
400     }
401 
402     /**
403      * {@inheritDoc}
404      */
405     @Override
406     public void setScheduledWriteMessages(int messages) {
407         super.setScheduledWriteMessages(messages);
408     }
409 
410     /**
411      * Update all statistical properties related with throughput.  By default
412      * this method returns silently without updating the throughput properties
413      * if they were calculated already within last
414      * {@link IoSessionConfig#getThroughputCalculationInterval() calculation interval}.
415      * If, however, <tt>force</tt> is specified as <tt>true</tt>, this method
416      * updates the throughput properties immediately.
417      * 
418      * @param force the flag that forces the update of properties immediately if <tt>true</tt>
419      */
420     public void updateThroughput(boolean force) {
421         super.updateThroughput(System.currentTimeMillis(), force);
422     }
423 }