Java tutorial
/* * Copyright (c) 2011-2013 The original author or authors * ------------------------------------------------------ * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.jsync.datagram.impl; import io.jsync.AsyncResult; import io.jsync.Handler; import io.jsync.buffer.Buffer; import io.jsync.datagram.DatagramSocket; import io.jsync.impl.AsyncInternal; import io.jsync.impl.DefaultFutureResult; import io.jsync.net.impl.ConnectionBase; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.DatagramPacket; import io.netty.channel.socket.InternetProtocolFamily; import io.netty.channel.socket.nio.NioDatagramChannel; import java.net.*; /** * @author <a href="mailto:nmaurer@redhat.com">Norman Maurer</a> */ public class DefaultDatagramSocket extends ConnectionBase implements DatagramSocket { protected boolean configurable = true; private Handler<Void> drainHandler; private Handler<io.jsync.datagram.DatagramPacket> dataHandler; @SuppressWarnings("deprecation") public DefaultDatagramSocket(AsyncInternal async, io.jsync.datagram.InternetProtocolFamily family) { super(async, createChannel(family), async.getOrCreateContext()); // Note: Look into why this has been deprecated... channel().config().setOption(ChannelOption.DATAGRAM_CHANNEL_ACTIVE_ON_REGISTRATION, true); context.getEventLoop().register(channel); channel.pipeline().addLast("handler", new DatagramServerHandler(this.async, this)); channel().config().setMaxMessagesPerRead(1); } private static NioDatagramChannel createChannel(io.jsync.datagram.InternetProtocolFamily family) { if (family == null) { return new NioDatagramChannel(); } switch (family) { case IPv4: return new NioDatagramChannel(InternetProtocolFamily.IPv4); case IPv6: return new NioDatagramChannel(InternetProtocolFamily.IPv6); default: return new NioDatagramChannel(); } } @Override public DatagramSocket listenMulticastGroup(String multicastAddress, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; try { addListener(channel().joinGroup(InetAddress.getByName(multicastAddress)), handler); } catch (UnknownHostException e) { notifyException(handler, e); } return this; } @Override public DatagramSocket listenMulticastGroup(String multicastAddress, String networkInterface, String source, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; try { InetAddress sourceAddress; if (source == null) { sourceAddress = null; } else { sourceAddress = InetAddress.getByName(source); } addListener(channel().joinGroup(InetAddress.getByName(multicastAddress), NetworkInterface.getByName(networkInterface), sourceAddress), handler); } catch (Exception e) { notifyException(handler, e); } return this; } @Override public DatagramSocket unlistenMulticastGroup(String multicastAddress, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; try { addListener(channel().leaveGroup(InetAddress.getByName(multicastAddress)), handler); } catch (UnknownHostException e) { notifyException(handler, e); } return this; } @Override public DatagramSocket unlistenMulticastGroup(String multicastAddress, String networkInterface, String source, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; try { InetAddress sourceAddress; if (source == null) { sourceAddress = null; } else { sourceAddress = InetAddress.getByName(source); } addListener(channel().leaveGroup(InetAddress.getByName(multicastAddress), NetworkInterface.getByName(networkInterface), sourceAddress), handler); } catch (Exception e) { notifyException(handler, e); } return this; } @Override public DatagramSocket blockMulticastGroup(String multicastAddress, String networkInterface, String sourceToBlock, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; try { InetAddress sourceAddress; if (sourceToBlock == null) { sourceAddress = null; } else { sourceAddress = InetAddress.getByName(sourceToBlock); } addListener(channel().block(InetAddress.getByName(multicastAddress), NetworkInterface.getByName(networkInterface), sourceAddress), handler); } catch (Exception e) { notifyException(handler, e); } return this; } @Override public DatagramSocket blockMulticastGroup(String multicastAddress, String sourceToBlock, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; try { addListener( channel().block(InetAddress.getByName(multicastAddress), InetAddress.getByName(sourceToBlock)), handler); } catch (UnknownHostException e) { notifyException(handler, e); } return this; } @Override public DatagramSocket listen(String address, int port, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; return listen(new InetSocketAddress(address, port), handler); } @Override public DatagramSocket listen(int port, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; return listen(new InetSocketAddress(port), handler); } @Override public DatagramSocket listen(InetSocketAddress local, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; ChannelFuture future = channel().bind(local); addListener(future, handler); return this; } @Override public DatagramSocket dataHandler(Handler<io.jsync.datagram.DatagramPacket> handler) { dataHandler = handler; return this; } final void handleMessage(io.jsync.datagram.DatagramPacket message) { if (dataHandler != null) { dataHandler.handle(message); } } @Override public DatagramSocket exceptionHandler(Handler<Throwable> handler) { exceptionHandler = handler; return this; } private void checkConfigurable() { if (!configurable) { throw new IllegalStateException("Can't set property after connect or bind has been called"); } } @SuppressWarnings("unchecked") final void addListener(ChannelFuture future, Handler<AsyncResult<DatagramSocket>> handler) { if (handler != null) { future.addListener(new DatagramChannelFutureListener<>(this, handler, async, context)); } } @SuppressWarnings("unchecked") public DatagramSocket pause() { doPause(); return this; } @SuppressWarnings("unchecked") public DatagramSocket resume() { doResume(); return this; } @Override protected void handleInterestedOpsChanged() { if (drainHandler != null) { drainHandler.handle(null); } } @Override @SuppressWarnings("unchecked") public DatagramSocket setWriteQueueMaxSize(int maxSize) { doSetWriteQueueMaxSize(maxSize); return this; } @Override public boolean writeQueueFull() { return doWriteQueueFull(); } @Override @SuppressWarnings("unchecked") public DatagramSocket drainHandler(Handler<Void> handler) { drainHandler = handler; return this; } @Override @SuppressWarnings("unchecked") public DatagramSocket send(Buffer packet, String host, int port, Handler<AsyncResult<DatagramSocket>> handler) { configurable = false; ChannelFuture future = channel() .writeAndFlush(new DatagramPacket(packet.getByteBuf(), new InetSocketAddress(host, port))); addListener(future, handler); return this; } @Override public DatagramSocket send(String str, String host, int port, Handler<AsyncResult<DatagramSocket>> handler) { return send(new Buffer(str), host, port, handler); } @Override public DatagramSocket send(String str, String enc, String host, int port, Handler<AsyncResult<DatagramSocket>> handler) { return send(new Buffer(str, enc), host, port, handler); } @Override public int getSendBufferSize() { return channel().config().getSendBufferSize(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setSendBufferSize(int sendBufferSize) { checkConfigurable(); channel().config().setSendBufferSize(sendBufferSize); return this; } @Override public int getReceiveBufferSize() { return channel().config().getReceiveBufferSize(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setReceiveBufferSize(int receiveBufferSize) { checkConfigurable(); channel().config().setReceiveBufferSize(receiveBufferSize); return this; } @Override public int getTrafficClass() { return channel().config().getTrafficClass(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setTrafficClass(int trafficClass) { checkConfigurable(); channel().config().setTrafficClass(trafficClass); return this; } @Override public boolean isReuseAddress() { return channel().config().isReuseAddress(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setReuseAddress(boolean reuseAddress) { checkConfigurable(); channel().config().setReuseAddress(reuseAddress); return this; } @Override public boolean isBroadcast() { return channel().config().isBroadcast(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setBroadcast(boolean broadcast) { checkConfigurable(); channel().config().setBroadcast(broadcast); return this; } @Override public boolean isMulticastLoopbackMode() { return channel().config().isLoopbackModeDisabled(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setMulticastLoopbackMode(boolean loopbackModeDisabled) { checkConfigurable(); channel().config().setLoopbackModeDisabled(loopbackModeDisabled); return this; } @Override public int getMulticastTimeToLive() { return channel().config().getTimeToLive(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setMulticastTimeToLive(int ttl) { checkConfigurable(); channel().config().setTimeToLive(ttl); return this; } @Override public String getMulticastNetworkInterface() { NetworkInterface iface = channel().config().getNetworkInterface(); if (iface == null) { return null; } return iface.getName(); } @Override @SuppressWarnings("unchecked") public DatagramSocket setMulticastNetworkInterface(String iface) { checkConfigurable(); try { channel().config().setNetworkInterface(NetworkInterface.getByName(iface)); } catch (SocketException e) { throw new IllegalArgumentException("Could not find network interface with name " + iface, e); } return this; } @Override public void close(final Handler<AsyncResult<Void>> handler) { // make sure everything is flushed out on close endReadAndFlush(); ChannelFuture future = channel.close(); if (handler != null) { future.addListener(new DatagramChannelFutureListener<>(null, handler, async, context)); } } protected DatagramChannel channel() { return (DatagramChannel) channel; } private void notifyException(final Handler<AsyncResult<DatagramSocket>> handler, final Throwable cause) { if (context.isOnCorrectWorker(channel().eventLoop())) { try { async.setContext(context); handler.handle(new DefaultFutureResult<DatagramSocket>(cause)); } catch (Throwable t) { context.reportException(t); } } else { context.execute(new Runnable() { public void run() { handler.handle(new DefaultFutureResult<DatagramSocket>(cause)); } }); } } }