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