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 package org.fusesource.hawtdispatch.transport;
018
019 import org.fusesource.hawtdispatch.DispatchQueue;
020 import org.fusesource.hawtdispatch.Task;
021
022 import java.net.*;
023 import java.nio.channels.DatagramChannel;
024
025 /**
026 * <p>
027 * </p>
028 *
029 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
030 */
031 public class UdpTransportServer extends ServiceBase implements TransportServer {
032
033 private final String bindScheme;
034 private final InetSocketAddress bindAddress;
035
036 private DatagramChannel channel;
037 private TransportServerListener listener;
038 private DispatchQueue dispatchQueue;
039
040 public UdpTransportServer(URI location) throws UnknownHostException {
041 bindScheme = location.getScheme();
042 String host = location.getHost();
043 host = (host == null || host.length() == 0) ? "::" : host;
044 bindAddress = new InetSocketAddress(InetAddress.getByName(host), location.getPort());
045 }
046
047 private UdpTransport transport;
048
049 public void setTransportServerListener(TransportServerListener listener) {
050 this.listener = listener;
051 }
052
053 public InetSocketAddress getSocketAddress() {
054 return (InetSocketAddress) channel.socket().getLocalSocketAddress();
055 }
056
057 public DispatchQueue getDispatchQueue() {
058 return dispatchQueue;
059 }
060
061 public void setDispatchQueue(DispatchQueue dispatchQueue) {
062 this.dispatchQueue = dispatchQueue;
063 }
064
065 @Override
066 protected void _start(Task onCompleted) {
067 accept();
068 if( onCompleted!=null ) {
069 dispatchQueue.execute(onCompleted);
070 }
071 }
072
073 private void queueAccept() {
074 dispatchQueue.execute(new Task() {
075 public void run() {
076 accept();
077 }
078 });
079 }
080
081 private void accept() {
082 if (getServiceState().isStarted() || getServiceState().isStarting()) {
083 try {
084 UdpTransport udpTransport = createTransport();
085 transport = udpTransport;
086 transport.onDispose = new Task() {
087 public void run() {
088 queueAccept();
089 }
090 };
091 channel = DatagramChannel.open();
092 channel.socket().bind(bindAddress);
093 transport.connected(channel);
094 listener.onAccept(transport);
095 } catch (Exception e) {
096 listener.onAcceptError(e);
097 }
098 }
099 }
100
101 protected UdpTransport createTransport() {
102 return new UdpTransport();
103 }
104
105 @Override
106 protected void _stop(Task onCompleted) {
107 transport.stop(onCompleted);
108 }
109
110 public void suspend() {
111 dispatchQueue.suspend();
112 }
113
114 public void resume() {
115 dispatchQueue.resume();
116 }
117
118 public String getBoundAddress() {
119 try {
120 String host = bindAddress.getAddress().getHostAddress();
121 int port = channel.socket().getLocalPort();
122 return new URI(bindScheme, null, host, port, null, null, null).toString();
123 } catch (URISyntaxException e) {
124 throw new RuntimeException(e);
125 }
126 }
127
128 /**
129 * @return pretty print of this
130 */
131 public String toString() {
132 return getBoundAddress();
133 }
134
135 }