001 /**
002 * Copyright (C) 2012 FuseSource, Inc.
003 * http://fusesource.com
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.fusesource.hawtdispatch.transport;
019
020 import org.fusesource.hawtdispatch.*;
021
022 import java.io.EOFException;
023 import java.io.IOException;
024 import java.net.SocketAddress;
025 import java.net.URI;
026 import java.util.LinkedList;
027 import java.util.concurrent.atomic.AtomicBoolean;
028
029 /**
030 *
031 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
032 */
033 public class PipeTransport implements Transport {
034 static private final Object EOF_TOKEN = new Object();
035
036 final private PipeTransportServer server;
037 PipeTransport peer;
038 private TransportListener listener;
039 private SocketAddress remoteAddress;
040 private AtomicBoolean stopping = new AtomicBoolean();
041 private String name;
042 private boolean marshal;
043 private boolean trace;
044
045 private DispatchQueue dispatchQueue;
046 private CustomDispatchSource<Object,LinkedList<Object>> dispatchSource;
047 private boolean connected;
048
049 private long writeCounter = 0;
050 private long readCounter = 0;
051 private ProtocolCodec protocolCodec;
052
053 public PipeTransport(PipeTransportServer server) {
054 this.server = server;
055 }
056
057 public DispatchQueue getDispatchQueue() {
058 return dispatchQueue;
059 }
060 public void setDispatchQueue(DispatchQueue queue) {
061 this.dispatchQueue = queue;
062 }
063
064 @Deprecated
065 public void start(final Runnable onCompleted) {
066 start(new TaskWrapper(onCompleted));
067 }
068 public void start(final Task onCompleted) {
069 if (dispatchQueue == null) {
070 throw new IllegalArgumentException("dispatchQueue is not set");
071 }
072 server.dispatchQueue.execute(new Task(){
073 public void run() {
074 dispatchSource = Dispatch.createSource(EventAggregators.linkedList(), dispatchQueue);
075 dispatchSource.setEventHandler(new Task() {
076 public void run() {
077 try {
078 final LinkedList<Object> commands = dispatchSource.getData();
079 for (Object o : commands) {
080
081 if (o == EOF_TOKEN) {
082 throw new EOFException();
083 }
084 readCounter++;
085 listener.onTransportCommand(o);
086 }
087
088 // let the peer know that they have been processed.
089 peer.dispatchQueue.execute(new Task() {
090 public void run() {
091 outbound -= commands.size();
092 drainInbound();
093 }
094 });
095 } catch (IOException e) {
096 listener.onTransportFailure(e);
097 }
098
099 }
100 });
101 if( peer.dispatchSource != null ) {
102 fireConnected();
103 peer.fireConnected();
104 }
105 if( onCompleted!=null ) {
106 onCompleted.run();
107 }
108
109 }
110 });
111 }
112
113 private void fireConnected() {
114 dispatchQueue.execute(new Task() {
115 public void run() {
116 connected = true;
117 dispatchSource.resume();
118 listener.onTransportConnected();
119 drainInbound();
120 }
121 });
122 }
123
124 public void flush() {
125 listener.onRefill();
126 }
127
128 @Deprecated
129 public void stop(final Runnable onCompleted) {
130 stop(new TaskWrapper(onCompleted));
131 }
132 public void stop(Task onCompleted) {
133 if( connected ) {
134 peer.dispatchSource.merge(EOF_TOKEN);
135 }
136 if( dispatchSource!=null ) {
137 dispatchSource.setCancelHandler(onCompleted);
138 dispatchSource.cancel();
139 }
140 setDispatchQueue(null);
141 }
142
143 static final class OneWay {
144 final Object command;
145 final Retained retained;
146
147 public OneWay(Object command, Retained retained) {
148 this.command = command;
149 this.retained = retained;
150 }
151 }
152
153 int outbound = 0;
154 int maxOutbound = 100;
155
156 public boolean full() {
157 return outbound >= maxOutbound;
158 }
159
160 public boolean offer(Object command) {
161 if( !connected ) {
162 return false;
163 }
164 if( full() ) {
165 return false;
166 } else {
167 transmit(command);
168 return true;
169 }
170 }
171
172 private void drainInbound() {
173 if( !full() ) {
174 listener.onRefill();
175 }
176 }
177
178 private void transmit(Object command) {
179 writeCounter++;
180 outbound++;
181 peer.dispatchSource.merge(command);
182 }
183
184 /**
185 * @return The number of objects sent by the transport.
186 */
187 public long getWriteCounter() {
188 return writeCounter;
189 }
190
191 /**
192 * @return The number of objects received by the transport.
193 */
194 public long getReadCounter() {
195 return readCounter;
196 }
197
198 public SocketAddress getLocalAddress() {
199 return remoteAddress;
200 }
201
202 public SocketAddress getRemoteAddress() {
203 return remoteAddress;
204 }
205
206 public void suspendRead() {
207 dispatchSource.suspend();
208 }
209
210 public void resumeRead() {
211 dispatchSource.resume();
212 }
213
214 public void setRemoteAddress(final String remoteAddress) {
215 this.remoteAddress = new SocketAddress() {
216 @Override
217 public String toString() {
218 return remoteAddress;
219 }
220 };
221 if (name == null) {
222 name = remoteAddress;
223 }
224 }
225
226 public void setName(String name) {
227 this.name = name;
228 }
229
230 public TransportListener getTransportListener() {
231 return listener;
232 }
233 public void setTransportListener(TransportListener transportListener) {
234 this.listener = transportListener;
235 }
236
237 public ProtocolCodec getProtocolCodec() {
238 return protocolCodec;
239 }
240 public void setProtocolCodec(ProtocolCodec protocolCodec) {
241 this.protocolCodec = protocolCodec;
242 }
243
244
245 public boolean isTrace() {
246 return trace;
247 }
248
249 public void setTrace(boolean trace) {
250 this.trace = trace;
251 }
252
253 public boolean isMarshal() {
254 return marshal;
255 }
256 public void setMarshal(boolean marshall) {
257 this.marshal = marshall;
258 }
259
260 public boolean isConnected() {
261 return !stopping.get();
262 }
263 public boolean isClosed() {
264 return false;
265 }
266 }