/**
* Copyright (C) 2012 FuseSource, Inc.
* http://fusesource.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fusesource.hawtdispatch.transport;
import org.fusesource.hawtdispatch.DispatchQueue;
import org.fusesource.hawtdispatch.Task;
import java.net.*;
import java.nio.channels.DatagramChannel;
import java.util.concurrent.Executor;
/**
* <p>
* </p>
*
* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
*/
public class UdpTransportServer extends ServiceBase implements TransportServer {
private final String bindScheme;
private final InetSocketAddress bindAddress;
private DatagramChannel channel;
private TransportServerListener listener;
private DispatchQueue dispatchQueue;
private Executor blockingExecutor;
public UdpTransportServer(URI location) throws UnknownHostException {
bindScheme = location.getScheme();
String host = location.getHost();
host = (host == null || host.length() == 0) ? "::" : host;
bindAddress = new InetSocketAddress(InetAddress.getByName(host), location.getPort());
}
private UdpTransport transport;
public void setTransportServerListener(TransportServerListener listener) {
this.listener = listener;
}
public InetSocketAddress getSocketAddress() {
return (InetSocketAddress) channel.socket().getLocalSocketAddress();
}
public DispatchQueue getDispatchQueue() {
return dispatchQueue;
}
public void setDispatchQueue(DispatchQueue dispatchQueue) {
this.dispatchQueue = dispatchQueue;
}
@Override
protected void _start(Task onCompleted) {
accept();
if( onCompleted!=null ) {
dispatchQueue.execute(onCompleted);
}
}
private void queueAccept() {
dispatchQueue.execute(new Task() {
public void run() {
accept();
}
});
}
private void accept() {
if (getServiceState().isStarted() || getServiceState().isStarting()) {
try {
UdpTransport udpTransport = createTransport();
transport = udpTransport;
transport.onDispose = new Task() {
public void run() {
queueAccept();
}
};
channel = DatagramChannel.open();
channel.socket().bind(bindAddress);
transport.connected(channel);
listener.onAccept(transport);
} catch (Exception e) {
listener.onAcceptError(e);
}
}
}
protected UdpTransport createTransport() {
final UdpTransport transport = new UdpTransport();
transport.setBlockingExecutor(blockingExecutor);
transport.setDispatchQueue(dispatchQueue);
return transport;
}
@Override
protected void _stop(Task onCompleted) {
transport.stop(onCompleted);
}
public void suspend() {
dispatchQueue.suspend();
}
public void resume() {
dispatchQueue.resume();
}
public String getBoundAddress() {
try {
String host = bindAddress.getAddress().getHostAddress();
int port = channel.socket().getLocalPort();
return new URI(bindScheme, null, host, port, null, null, null).toString();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
/**
* @return pretty print of this
*/
public String toString() {
return getBoundAddress();
}
public Executor getBlockingExecutor() {
return blockingExecutor;
}
public void setBlockingExecutor(Executor blockingExecutor) {
this.blockingExecutor = blockingExecutor;
}
}