1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.transport.serial;
21
22 import gnu.io.SerialPort;
23 import gnu.io.SerialPortEvent;
24 import gnu.io.SerialPortEventListener;
25 import gnu.io.UnsupportedCommOperationException;
26
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.util.TooManyListenersException;
31
32 import org.apache.mina.core.buffer.IoBuffer;
33 import org.apache.mina.core.filterchain.DefaultIoFilterChain;
34 import org.apache.mina.core.filterchain.IoFilterChain;
35 import org.apache.mina.core.service.DefaultTransportMetadata;
36 import org.apache.mina.core.service.IoProcessor;
37 import org.apache.mina.core.service.IoServiceListenerSupport;
38 import org.apache.mina.core.service.TransportMetadata;
39 import org.apache.mina.core.session.AbstractIoSession;
40 import org.apache.mina.core.write.WriteRequest;
41 import org.apache.mina.util.ExceptionMonitor;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45
46
47
48
49
50 class SerialSessionImpl extends AbstractIoSession implements SerialSession, SerialPortEventListener {
51
52 static final TransportMetadata METADATA = new DefaultTransportMetadata("rxtx", "serial", false, true,
53 SerialAddress.class, SerialSessionConfig.class, IoBuffer.class);
54
55 private final IoProcessor<SerialSessionImpl> processor = new SerialIoProcessor();
56
57 private final IoFilterChain filterChain;
58
59 private final IoServiceListenerSupport serviceListeners;
60
61 private final SerialAddress address;
62
63 private final SerialPort port;
64
65 private final Logger log;
66
67 private InputStream inputStream;
68
69 private OutputStream outputStream;
70
71 SerialSessionImpl(SerialConnector service, IoServiceListenerSupport serviceListeners, SerialAddress address,
72 SerialPort port) {
73 super(service);
74 config = new DefaultSerialSessionConfig();
75 this.serviceListeners = serviceListeners;
76 filterChain = new DefaultIoFilterChain(this);
77 this.port = port;
78 this.address = address;
79
80 log = LoggerFactory.getLogger(SerialSessionImpl.class);
81 }
82
83 public SerialSessionConfig getConfig() {
84 return (SerialSessionConfig) config;
85 }
86
87 public IoFilterChain getFilterChain() {
88 return filterChain;
89 }
90
91 public TransportMetadata getTransportMetadata() {
92 return METADATA;
93 }
94
95 public SerialAddress getLocalAddress() {
96 return null;
97 }
98
99 public SerialAddress getRemoteAddress() {
100 return address;
101 }
102
103 @Override
104 public SerialAddress getServiceAddress() {
105 return (SerialAddress) super.getServiceAddress();
106 }
107
108 public void setDTR(boolean dtr) {
109 port.setDTR(dtr);
110 }
111
112 public boolean isDTR() {
113 return port.isDTR();
114 }
115
116 public void setRTS(boolean rts) {
117 port.setRTS(rts);
118 }
119
120 public boolean isRTS() {
121 return port.isRTS();
122 }
123
124
125
126
127
128
129
130 void start() throws IOException, TooManyListenersException {
131 inputStream = port.getInputStream();
132 outputStream = port.getOutputStream();
133 ReadWorker w = new ReadWorker();
134 w.start();
135 port.addEventListener(this);
136 ((SerialConnector) getService()).getIdleStatusChecker0().addSession(this);
137 try {
138 getService().getFilterChainBuilder().buildFilterChain(getFilterChain());
139 serviceListeners.fireSessionCreated(this);
140 } catch (Throwable e) {
141 getFilterChain().fireExceptionCaught(e);
142 processor.remove(this);
143 }
144 }
145
146 private final Object writeMonitor = new Object();
147
148 private WriteWorker writeWorker;
149
150 private class WriteWorker extends Thread {
151 @Override
152 public void run() {
153 while (isConnected() && !isClosing()) {
154 flushWrites();
155
156
157 synchronized (writeMonitor) {
158 try {
159 writeMonitor.wait();
160 } catch (InterruptedException e) {
161 log.error("InterruptedException", e);
162 }
163 }
164 }
165 }
166 }
167
168 private void flushWrites() {
169 for (;;) {
170 WriteRequest req = getCurrentWriteRequest();
171 if (req == null) {
172 req = getWriteRequestQueue().poll(this);
173 if (req == null) {
174 break;
175 }
176 }
177
178 IoBuffer buf = (IoBuffer) req.getMessage();
179 if (buf.remaining() == 0) {
180 setCurrentWriteRequest(null);
181 buf.reset();
182 this.getFilterChain().fireMessageSent(req);
183 continue;
184 }
185
186 int writtenBytes = buf.remaining();
187 try {
188 outputStream.write(buf.array(), buf.position(), writtenBytes);
189 buf.position(buf.position() + writtenBytes);
190
191
192 increaseWrittenBytes(writtenBytes, System.currentTimeMillis());
193
194 setCurrentWriteRequest(null);
195 buf.reset();
196
197
198 getFilterChain().fireMessageSent(req);
199 } catch (IOException e) {
200 this.getFilterChain().fireExceptionCaught(e);
201 }
202
203 }
204 }
205
206 private final Object readReadyMonitor = new Object();
207
208 private class ReadWorker extends Thread {
209 @Override
210 public void run() {
211 while (isConnected() && !isClosing()) {
212 synchronized (readReadyMonitor) {
213 try {
214 readReadyMonitor.wait();
215 } catch (InterruptedException e) {
216 log.error("InterruptedException", e);
217 }
218 if (isClosing() || !isConnected()) {
219 break;
220 }
221 int dataSize;
222 try {
223 dataSize = inputStream.available();
224 byte[] data = new byte[dataSize];
225 int readBytes = inputStream.read(data);
226
227 if (readBytes > 0) {
228 IoBuffer buf = IoBuffer.wrap(data, 0, readBytes);
229 buf.put(data, 0, readBytes);
230 buf.flip();
231 getFilterChain().fireMessageReceived(buf);
232 }
233 } catch (IOException e) {
234 getFilterChain().fireExceptionCaught(e);
235 }
236 }
237 }
238 }
239 }
240
241 public void serialEvent(SerialPortEvent evt) {
242 if (evt.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
243 synchronized (readReadyMonitor) {
244 readReadyMonitor.notifyAll();
245 }
246 }
247 }
248
249 @Override
250 public IoProcessor<SerialSessionImpl> getProcessor() {
251 return processor;
252 }
253
254 private class SerialIoProcessor implements IoProcessor<SerialSessionImpl> {
255 public void add(SerialSessionImpl session) {
256
257 }
258
259 public void flush(SerialSessionImpl session) {
260 if (writeWorker == null) {
261 writeWorker = new WriteWorker();
262 writeWorker.start();
263 } else {
264 synchronized (writeMonitor) {
265 writeMonitor.notifyAll();
266 }
267 }
268 }
269
270 public void remove(SerialSessionImpl session) {
271 try {
272 inputStream.close();
273 } catch (IOException e) {
274 ExceptionMonitor.getInstance().exceptionCaught(e);
275 }
276 try {
277 outputStream.close();
278 } catch (IOException e) {
279 ExceptionMonitor.getInstance().exceptionCaught(e);
280 }
281
282 try {
283 port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
284 } catch (UnsupportedCommOperationException e) {
285 ExceptionMonitor.getInstance().exceptionCaught(e);
286 }
287
288 port.close();
289 flush(session);
290 synchronized (readReadyMonitor) {
291 readReadyMonitor.notifyAll();
292 }
293
294 serviceListeners.fireSessionDestroyed(SerialSessionImpl.this);
295 }
296
297 public void updateTrafficControl(SerialSessionImpl session) {
298 throw new UnsupportedOperationException();
299 }
300
301 public void dispose() {
302
303 }
304
305 public boolean isDisposed() {
306 return false;
307 }
308
309 public boolean isDisposing() {
310 return false;
311 }
312 }
313 }