All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.grizzly.UDPConnectorHandler Maven / Gradle / Ivy

There is a newer version: 10.0-b28
Show newest version
/*
 * 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 */

package com.sun.grizzly;

import com.sun.grizzly.async.AsyncQueueDataProcessor;
import com.sun.grizzly.async.AsyncQueueReadable;
import com.sun.grizzly.async.AsyncWriteCallbackHandler;
import com.sun.grizzly.async.AsyncQueueWritable;
import com.sun.grizzly.async.AsyncReadCallbackHandler;
import com.sun.grizzly.async.AsyncReadCondition;
import com.sun.grizzly.util.InputReader;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AlreadyConnectedException;
import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.DatagramChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

/**
 * Client side interface used to implement non blocking client operation.
 * Implementation of this class must make sure the following methods are
 * invoked in that order:
 * 


 * (1) connect()
 * (2) read() or write().
 * 

* * @author Jeanfrancois Arcand */ public class UDPConnectorHandler implements ConnectorHandler, AsyncQueueWritable, AsyncQueueReadable { /** * The underlying UDPSelectorHandler used to mange SelectionKeys. */ protected UDPSelectorHandler selectorHandler; /** * A {@link CallbackHandler} handler invoked by the UDPSelectorHandler * when a non blocking operation is ready to be processed. */ protected CallbackHandler callbackHandler; /** * The connection's DatagramChannel. */ protected DatagramChannel datagramChannel; /** * Is the connection established. */ protected volatile boolean isConnected; /** * The internal Controller used (in case not specified). */ protected Controller controller; /** * IsConnected Latch related */ protected CountDownLatch isConnectedLatch; /** * Are we creating a controller every run. */ private boolean isStandalone = false; /** * A blocking {@link InputStream} that use a pool of Selector * to execute a blocking read operation. */ protected InputReader inputStream; /** * Connect to hostname:port. When an aysnchronous event happens (e.g * OP_READ or OP_WRITE), the {@link Controller} will invoke * the CallBackHandler. * @param remoteAddress remote address to connect * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when * a non blocking operation is ready to be handled. When null, all * read and write operation will be delegated to the default * {@link ProtocolChain} and its list of {@link ProtocolFilter} * . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}. */ public void connect(SocketAddress remoteAddress, CallbackHandler callbackHandler) throws IOException { connect(remoteAddress,null,callbackHandler); } /** * Connect to hostname:port. When an aysnchronous event happens (e.g * OP_READ or OP_WRITE), the {@link Controller} will invoke * the CallBackHandler. * @param remoteAddress remote address to connect * @param localAddress local address to bind * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when * a non blocking operation is ready to be handled. When null, all * read and write operation will be delegated to the default * {@link ProtocolChain} and its list of {@link ProtocolFilter} * . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}. */ public void connect(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler) throws IOException { if (controller == null){ throw new IllegalStateException("Controller cannot be null"); } connect(remoteAddress,localAddress,callbackHandler, (UDPSelectorHandler)controller.getSelectorHandler(protocol())); } /** * Connect to hostname:port. When an aysnchronous event happens (e.g * OP_READ or OP_WRITE), the {@link Controller} will invoke * the CallBackHandler. * @param remoteAddress remote address to connect * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when * a non blocking operation is ready to be handled. When null, all * read and write operation will be delegated to the default * {@link ProtocolChain} and its list of {@link ProtocolFilter} * . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}. * @param selectorHandler an instance of SelectorHandler. */ public void connect(SocketAddress remoteAddress, CallbackHandler callbackHandler, UDPSelectorHandler selectorHandler) throws IOException { connect(remoteAddress,null,callbackHandler,selectorHandler); } /** * Connect to hostname:port. When an aysnchronous event happens (e.g * OP_READ or OP_WRITE), the {@link Controller} will invoke * the CallBackHandler. * @param remoteAddress remote address to connect * @param localAddress local address to bin * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when * a non blocking operation is ready to be handled. When null, all * read and write operation will be delegated to the default * {@link ProtocolChain} and its list of {@link ProtocolFilter} * . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}. * @param selectorHandler an instance of SelectorHandler. */ public void connect(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler, UDPSelectorHandler selectorHandler) throws IOException { if (isConnected){ throw new AlreadyConnectedException(); } if (controller == null){ throw new IllegalStateException("Controller cannot be null"); } if (selectorHandler == null){ throw new IllegalStateException("Controller cannot be null"); } this.selectorHandler = selectorHandler; if (callbackHandler == null){ callbackHandler = new DefaultCallbackHandler(this); } else { this.callbackHandler = callbackHandler; } // Wait for the onConnect to be invoked. isConnectedLatch = new CountDownLatch(1); selectorHandler.connect(remoteAddress,localAddress,callbackHandler); try { isConnectedLatch.await(30, TimeUnit.SECONDS); } catch (InterruptedException ex) { throw new IOException(ex.getMessage()); } } /** * Connect to hostname:port. Internally an instance of Controller and * its default SelectorHandler will be created everytime this method is * called. This method should be used only and only if no external * Controller has been initialized. * @param remoteAddress remote address to connect */ public void connect(SocketAddress remoteAddress) throws IOException { connect(remoteAddress,(SocketAddress)null); } /** * Connect to hostname:port. Internally an instance of Controller and * its default SelectorHandler will be created everytime this method is * called. This method should be used only and only if no external * Controller has been initialized. * @param remoteAddress remote address to connect * @param localAddress local address to bin */ public void connect(SocketAddress remoteAddress, SocketAddress localAddress) throws IOException { if (isConnected){ throw new AlreadyConnectedException(); } if (controller == null){ isStandalone = true; controller = new Controller(); controller.setSelectorHandler(new UDPSelectorHandler(true)); DefaultPipeline pipeline = new DefaultPipeline(); pipeline.initPipeline(); pipeline.startPipeline(); controller.setPipeline(pipeline); final CountDownLatch latch = new CountDownLatch(1); controller.addStateListener(new ControllerStateListenerAdapter() { @Override public void onReady() { latch.countDown(); } @Override public void onException(Throwable e) { latch.countDown(); } }); callbackHandler = new DefaultCallbackHandler(this, false); new Thread(controller, "GrizzlyUDPConnectorHandler-Controller").start(); try { latch.await(); } catch (InterruptedException ex) { } } connect(remoteAddress,localAddress,callbackHandler, (UDPSelectorHandler)controller.getSelectorHandler(protocol())); } /** * Read bytes. If blocking is set to true, a pool of temporary * {@link Selector} will be used to read bytes. * @param byteBuffer The byteBuffer to store bytes. * @param blocking true if a a pool of temporary Selector * is required to handle a blocking read. */ public long read(ByteBuffer byteBuffer, boolean blocking) throws IOException { if (!isConnected){ throw new NotYetConnectedException(); } SelectionKey key = datagramChannel.keyFor(selectorHandler.getSelector()); if (blocking){ if (inputStream == null) { inputStream = new InputReader(); } inputStream.setSelectionKey(key); inputStream.setChannelType( InputReader.ChannelType.DatagramChannel); int nRead = inputStream.read(byteBuffer); return nRead; } else { if (callbackHandler == null){ throw new IllegalStateException ("Non blocking read needs a CallbackHandler"); } int nRead = datagramChannel.read(byteBuffer); if (nRead == 0){ selectorHandler.register(key, SelectionKey.OP_READ); } return nRead; } } /** * Writes bytes. If blocking is set to true, a pool of temporary * {@link Selector} will be used to writes bytes. * @param byteBuffer The byteBuffer to write. * @param blocking true if a a pool of temporary Selector * is required to handle a blocking write. */ public long write(ByteBuffer byteBuffer, boolean blocking) throws IOException { if (!isConnected){ throw new NotYetConnectedException(); } if (blocking){ throw new IllegalStateException("Blocking mode not supported"); } else { if (callbackHandler == null){ throw new IllegalStateException ("Non blocking write needs a CallbackHandler"); } SelectionKey key = datagramChannel.keyFor(selectorHandler.getSelector()); int nWrite = datagramChannel.write(byteBuffer); if (nWrite == 0){ selectorHandler.register(key, SelectionKey.OP_WRITE); } return nWrite; } } /** * {@inheritDoc} */ public void readFromAsyncQueue(ByteBuffer buffer, AsyncReadCallbackHandler callbackHandler) throws IOException { readFromAsyncQueue(buffer, callbackHandler, null); } /** * {@inheritDoc} */ public void readFromAsyncQueue(ByteBuffer buffer, AsyncReadCallbackHandler callbackHandler, AsyncReadCondition condition) throws IOException { readFromAsyncQueue(buffer, callbackHandler, condition, null); } /** * {@inheritDoc} */ public void readFromAsyncQueue(ByteBuffer buffer, AsyncReadCallbackHandler callbackHandler, AsyncReadCondition condition, AsyncQueueDataProcessor readPostProcessor) throws IOException { selectorHandler.getAsyncQueueReader().read( datagramChannel.keyFor(selectorHandler.getSelector()), buffer, callbackHandler, condition, readPostProcessor); } /** * {@inheritDoc} */ public void writeToAsyncQueue(ByteBuffer buffer) throws IOException { writeToAsyncQueue(buffer, null); } /** * {@inheritDoc} */ public void writeToAsyncQueue(ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler) throws IOException { writeToAsyncQueue(buffer, callbackHandler, null); } /** * {@inheritDoc} */ public void writeToAsyncQueue(ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor) throws IOException { writeToAsyncQueue(buffer, callbackHandler, writePreProcessor, false); } /** * {@inheritDoc} */ public void writeToAsyncQueue(ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor, boolean isCloneByteBuffer) throws IOException { selectorHandler.getAsyncQueueWriter().write( datagramChannel.keyFor(selectorHandler.getSelector()), buffer, callbackHandler, writePreProcessor, isCloneByteBuffer); } /** * {@inheritDoc} */ public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer) throws IOException { writeToAsyncQueue(dstAddress, buffer, null); } /** * {@inheritDoc} */ public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler) throws IOException { writeToAsyncQueue(dstAddress, buffer, callbackHandler, null); } /** * {@inheritDoc} */ public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor) throws IOException { writeToAsyncQueue(dstAddress, buffer, callbackHandler, writePreProcessor, false); } /** * {@inheritDoc} */ public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor, boolean isCloneByteBuffer) throws IOException { selectorHandler.getAsyncQueueWriter().write( datagramChannel.keyFor(selectorHandler.getSelector()), dstAddress, buffer, callbackHandler, writePreProcessor, isCloneByteBuffer); } /** * Receive bytes. * @param byteBuffer The byteBuffer to store bytes. * @param socketAddress * @return number bytes sent * @throws java.io.IOException */ public long send(ByteBuffer byteBuffer, SocketAddress socketAddress) throws IOException { if (!isConnected){ throw new NotYetConnectedException(); } if (callbackHandler == null){ throw new IllegalStateException ("Non blocking read needs a CallbackHandler"); } return datagramChannel.send(byteBuffer,socketAddress); } /** * Receive bytes. * @param byteBuffer The byteBuffer to store bytes. * @return {@link SocketAddress} * @throws java.io.IOException */ public SocketAddress receive(ByteBuffer byteBuffer) throws IOException { if (!isConnected){ throw new NotYetConnectedException(); } SelectionKey key = datagramChannel.keyFor(selectorHandler.getSelector()); if (callbackHandler == null){ throw new IllegalStateException ("Non blocking read needs a CallbackHandler"); } SocketAddress socketAddress = datagramChannel.receive(byteBuffer); return socketAddress; } /** * Close the underlying connection. */ public void close() throws IOException{ if (datagramChannel != null){ if (selectorHandler != null){ SelectionKey key = datagramChannel.keyFor(selectorHandler.getSelector()); if (key == null) return; selectorHandler.getSelectionKeyHandler().cancel(key); } else { datagramChannel.close(); } } if (controller != null && isStandalone){ controller.stop(); controller = null; } isStandalone = false; isConnected = false; } /** * Finish handling the OP_CONNECT interest ops. */ public void finishConnect(SelectionKey key) throws IOException { if (Controller.logger().isLoggable(Level.FINE)) { Controller.logger().log(Level.FINE, "Finish connect"); } datagramChannel = (DatagramChannel)key.channel(); isConnected = datagramChannel.isConnected(); if (isConnectedLatch != null) { isConnectedLatch.countDown(); } } /** * A token decribing the protocol supported by an implementation of this * interface */ public Controller.Protocol protocol(){ return Controller.Protocol.UDP; } /** * Is the underlying DatagramChannel connected. * @return true if connected, othewise false */ public boolean isConnected(){ return isConnected && datagramChannel.isOpen(); } /** * Return the {@link Controller} * @return the {@link Controller} */ public Controller getController() { return controller; } /** * Set the {@link Controller} to use with this instance. * @param controller the {@link Controller} to use with this instance. */ public void setController(Controller controller) { this.controller = controller; } /** * Return the current {@link SocketChannel} used. * @return the current {@link SocketChannel} used. */ public SelectableChannel getUnderlyingChannel() { return datagramChannel; } /** * Return the {@link CallbackHandler}. * @return the {@link CallbackHandler}. */ public CallbackHandler getCallbackHandler() { return callbackHandler; } /** * Set the {@link CallbackHandler}. * @param callbackHandler the {@link CallbackHandler}. */ public void setCallbackHandler(CallbackHandler callbackHandler) { this.callbackHandler = callbackHandler; } /** * Return the associated {@link SelectorHandler}. * @return the associated {@link SelectorHandler}. */ public UDPSelectorHandler getSelectorHandler() { return selectorHandler; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy