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.transport.vmpipe.support;
21  
22  import java.util.Queue;
23  import java.util.concurrent.ConcurrentLinkedQueue;
24  
25  import org.apache.mina.common.ByteBuffer;
26  import org.apache.mina.common.IdleStatus;
27  import org.apache.mina.common.IoSession;
28  import org.apache.mina.common.IoFilter.WriteRequest;
29  import org.apache.mina.common.support.AbstractIoFilterChain;
30  
31  /**
32   * @author The Apache Directory Project (mina-dev@directory.apache.org)
33   * @version $Rev: 575603 $, $Date: 2007-09-14 19:04:45 +0900 (Fri, 14 Sep 2007) $
34   */
35  public class VmPipeFilterChain extends AbstractIoFilterChain {
36  
37      private final Queue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
38  
39      private volatile boolean flushEnabled;
40      private volatile boolean sessionOpened;
41  
42      public VmPipeFilterChain(IoSession session) {
43          super(session);
44      }
45  
46      public void start() {
47          flushEnabled = true;
48          flushEvents();
49          flushPendingDataQueues( (VmPipeSessionImpl) getSession() );
50      }
51  
52      private void pushEvent(Event e) {
53          eventQueue.offer(e);
54          if ( flushEnabled ) {
55              flushEvents();
56          }
57      }
58  
59      private void flushEvents() {
60          Event e;
61          while ((e = eventQueue.poll()) != null) {
62              fireEvent(e);
63          }
64      }
65  
66      private void fireEvent(Event e) {
67          IoSession session = getSession();
68          EventType type = e.getType();
69          Object data = e.getData();
70  
71          if (type == EventType.RECEIVED) {
72              VmPipeSessionImpl s = (VmPipeSessionImpl) session;
73  
74              if( sessionOpened && s.getTrafficMask().isReadable() && s.getLock().tryLock()) {
75                  try {
76                      int byteCount = 1;
77                      if (data instanceof ByteBuffer) {
78                          byteCount = ((ByteBuffer) data).remaining();
79                      }
80  
81                      s.increaseReadBytes(byteCount);
82  
83                      super.fireMessageReceived(s, data);
84                  } finally {
85                      s.getLock().unlock();
86                  }
87  
88                  flushPendingDataQueues( s );
89              } else {
90                  s.pendingDataQueue.add(data);
91              }
92          } else if (type == EventType.WRITE) {
93              super.fireFilterWrite(session, (WriteRequest) data);
94          } else if (type == EventType.SENT) {
95              super.fireMessageSent(session, (WriteRequest) data);
96          } else if (type == EventType.EXCEPTION) {
97              super.fireExceptionCaught(session, (Throwable) data);
98          } else if (type == EventType.IDLE) {
99              super.fireSessionIdle(session, (IdleStatus) data);
100         } else if (type == EventType.OPENED) {
101             super.fireSessionOpened(session);
102             sessionOpened = true;
103         } else if (type == EventType.CREATED) {
104             super.fireSessionCreated(session);
105         } else if (type == EventType.CLOSED) {
106             super.fireSessionClosed(session);
107         } else if (type == EventType.CLOSE) {
108             super.fireFilterClose(session);
109         }
110     }
111 
112     private static void flushPendingDataQueues( VmPipeSessionImpl s ) {
113         s.updateTrafficMask();
114         s.getRemoteSession().updateTrafficMask();
115     }
116 
117     @Override
118     public void fireFilterClose(IoSession session) {
119         pushEvent(new Event(EventType.CLOSE, null));
120     }
121 
122     @Override
123     public void fireFilterWrite(IoSession session, WriteRequest writeRequest) {
124         pushEvent(new Event(EventType.WRITE, writeRequest));
125     }
126 
127     @Override
128     public void fireExceptionCaught(IoSession session, Throwable cause) {
129         pushEvent(new Event(EventType.EXCEPTION, cause));
130     }
131 
132     @Override
133     public void fireMessageSent(IoSession session, WriteRequest request) {
134         pushEvent(new Event(EventType.SENT, request));
135     }
136 
137     @Override
138     public void fireSessionClosed(IoSession session) {
139         pushEvent(new Event(EventType.CLOSED, null));
140     }
141 
142     @Override
143     public void fireSessionCreated(IoSession session) {
144         pushEvent(new Event(EventType.CREATED, null));
145     }
146 
147     @Override
148     public void fireSessionIdle(IoSession session, IdleStatus status) {
149         pushEvent(new Event(EventType.IDLE, status));
150     }
151 
152     @Override
153     public void fireSessionOpened(IoSession session) {
154         pushEvent(new Event(EventType.OPENED, null));
155     }
156 
157     @Override
158     public void fireMessageReceived(IoSession session, Object message) {
159         pushEvent(new Event(EventType.RECEIVED, message));
160     }
161 
162     @Override
163     protected void doWrite(IoSession session, WriteRequest writeRequest) {
164         VmPipeSessionImpl s = (VmPipeSessionImpl) session;
165         if (s.isConnected()) {
166             if ( s.getTrafficMask().isWritable() && s.getLock().tryLock()) {
167                 try {
168                     Object message = writeRequest.getMessage();
169 
170                     int byteCount = 1;
171                     Object messageCopy = message;
172                     if (message instanceof ByteBuffer) {
173                         ByteBuffer rb = (ByteBuffer) message;
174                         rb.mark();
175                         byteCount = rb.remaining();
176                         ByteBuffer wb = ByteBuffer.allocate(rb.remaining());
177                         wb.put(rb);
178                         wb.flip();
179                         rb.reset();
180                         messageCopy = wb;
181                     }
182 
183                     // Avoid unwanted side effect that scheduledWrite* becomes negative
184                     // by increasing them.
185                     s.increaseScheduledWriteBytes(byteCount);
186                     s.increaseScheduledWriteRequests();
187                     
188                     s.increaseWrittenBytes(byteCount);
189                     s.increaseWrittenMessages();
190 
191                     s.getRemoteSession().getFilterChain().fireMessageReceived(
192                         s.getRemoteSession(), messageCopy);
193                     s.getFilterChain().fireMessageSent(s, writeRequest);
194                 } finally {
195                     s.getLock().unlock();
196                 }
197 
198                 flushPendingDataQueues( s );
199             } else {
200                 s.pendingDataQueue.add(writeRequest);
201             }
202         } else {
203             writeRequest.getFuture().setWritten(false);
204         }
205     }
206 
207     @Override
208     protected void doClose(IoSession session) {
209         VmPipeSessionImpl s = (VmPipeSessionImpl) session;
210 
211         try {
212             s.getLock().lock();
213 
214             if (!session.getCloseFuture().isClosed()) {
215                 s.getServiceListeners().fireSessionDestroyed(s);
216                 s.getRemoteSession().close();
217             }
218         } finally {
219             s.getLock().unlock();
220         }
221     }
222 
223     // FIXME Copied and pasted from {@link ExecutorFilter}.
224     private static class EventType {
225         public static final EventType CREATED = new EventType("CREATED");
226 
227         public static final EventType OPENED = new EventType("OPENED");
228 
229         public static final EventType CLOSED = new EventType("CLOSED");
230 
231         public static final EventType RECEIVED = new EventType("RECEIVED");
232 
233         public static final EventType SENT = new EventType("SENT");
234 
235         public static final EventType IDLE = new EventType("IDLE");
236 
237         public static final EventType EXCEPTION = new EventType("EXCEPTION");
238 
239         public static final EventType WRITE = new EventType("WRITE");
240 
241         public static final EventType CLOSE = new EventType("CLOSE");
242 
243         private final String value;
244 
245         private EventType(String value) {
246             this.value = value;
247         }
248 
249         @Override
250         public String toString() {
251             return value;
252         }
253     }
254 
255     private static class Event {
256         private final EventType type;
257 
258         private final Object data;
259 
260         private Event(EventType type, Object data) {
261             this.type = type;
262             this.data = data;
263         }
264 
265         public Object getData() {
266             return data;
267         }
268 
269         public EventType getType() {
270             return type;
271         }
272     }
273 }