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