com.sun.grizzly.connectioncache.client.CacheableConnectorHandler Maven / Gradle / Ivy
/*
*
* 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.connectioncache.client;
import com.sun.grizzly.AbstractConnectorHandler;
import com.sun.grizzly.CallbackHandler;
import com.sun.grizzly.CallbackHandlerSelectionKeyAttachment;
import com.sun.grizzly.ConnectorHandler;
import com.sun.grizzly.Context;
import com.sun.grizzly.Controller;
import com.sun.grizzly.Controller.Protocol;
import com.sun.grizzly.DefaultCallbackHandler;
import com.sun.grizzly.IOEvent;
import com.sun.grizzly.NIOContext;
import com.sun.grizzly.SelectorHandler;
import com.sun.grizzly.async.AsyncQueueDataProcessor;
import com.sun.grizzly.async.AsyncQueueReadUnit;
import com.sun.grizzly.async.AsyncQueueWriteUnit;
import com.sun.grizzly.async.AsyncReadCallbackHandler;
import com.sun.grizzly.async.AsyncReadCondition;
import com.sun.grizzly.async.AsyncWriteCallbackHandler;
import com.sun.grizzly.async.ByteBufferCloner;
import com.sun.grizzly.connectioncache.spi.transport.ContactInfo;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.util.concurrent.Future;
/**
* Extended implementation of the DefaultSelectionKeyHandler with
* ConnectionManagement integrated in it
*
* @author Alexey Stashok
*/
public class CacheableConnectorHandler
extends AbstractConnectorHandler {
private SocketAddress targetAddress;
private final CacheableConnectorHandlerPool parentPool;
private ConnectorHandler underlyingConnectorHandler;
private final ConnectExecutor connectExecutor;
public CacheableConnectorHandler(CacheableConnectorHandlerPool parentPool) {
this.parentPool = parentPool;
connectExecutor = new ConnectExecutor();
}
// connect method #1
public void connect(SocketAddress remoteAddress, CallbackHandler callbackHandler, SelectorHandler selectorHandler) throws IOException {
connectExecutor.setParameters(remoteAddress, callbackHandler, selectorHandler);
doConnect(remoteAddress);
}
// connect method #2
public void connect(SocketAddress remoteAddress, CallbackHandler callbackHandler) throws IOException {
connectExecutor.setParameters(remoteAddress, callbackHandler);
doConnect(remoteAddress);
}
// connect method #3
public void connect(SocketAddress remoteAddress) throws IOException {
connectExecutor.setParameters(remoteAddress);
doConnect(remoteAddress);
}
// connect method #4
public void connect(SocketAddress remoteAddress, SocketAddress localAddress,
CallbackHandler callbackHandler, SelectorHandler selectorHandler) throws IOException {
connectExecutor.setParameters(remoteAddress, localAddress, callbackHandler, selectorHandler);
doConnect(remoteAddress);
}
// connect method #5
public void connect(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler) throws IOException {
connectExecutor.setParameters(remoteAddress, localAddress, callbackHandler);
doConnect(remoteAddress);
}
// connect method #6
public void connect(SocketAddress remoteAddress, SocketAddress localAddress) throws IOException {
connectExecutor.setParameters(remoteAddress, localAddress);
doConnect(remoteAddress);
}
/**
* Releases underlying connection, which means it could be reused for writing
* by other CacheableConnectorHandler, however this
* CacheableConnectorHandler will be still interested in getting
* expectedResponseCount responses on it.
*
* @param expectedResponseCount number of reponses expected on the connection
*/
public void release(int expectedResponseCount) {
parentPool.getOutboundConnectionCache().release(underlyingConnectorHandler, expectedResponseCount);
}
/**
* Notifies connection cache, that response was received. And connection cache
* could decrease expected response counter by 1
*/
public void responseReceived() {
parentPool.getOutboundConnectionCache().responseReceived(underlyingConnectorHandler);
}
/**
* @param targetAddress target connection address
* @throws java.io.IOException if IO error happened
*/
private void doConnect(SocketAddress targetAddress) throws IOException {
this.targetAddress = targetAddress;
callbackHandler = connectExecutor.callbackHandler;
if (callbackHandler == null) {
callbackHandler = new DefaultCallbackHandler(this);
}
underlyingConnectorHandler = parentPool.
getOutboundConnectionCache().get(
new CacheableConnectorInfo(parentPool, connectExecutor,
protocol, targetAddress),
parentPool.getConnectionFinder());
/* check whether NEW connection was created, or taken from cache */
if (!connectExecutor.wasCalled()) { // if taken from cache
//if connection is taken from cache - explicitly notify callback handler
underlyingConnectorHandler.setCallbackHandler(callbackHandler);
notifyCallbackHandlerPseudoConnect();
}
}
public void close() throws IOException {
parentPool.getOutboundConnectionCache().release(underlyingConnectorHandler, 0);
}
@Override
public long read(ByteBuffer byteBuffer, boolean blocking) throws IOException {
return underlyingConnectorHandler.read(byteBuffer, blocking);
}
@Override
public long write(ByteBuffer byteBuffer, boolean blocking) throws IOException {
return underlyingConnectorHandler.write(byteBuffer, blocking);
}
public void finishConnect(SelectionKey key) {
// Call underlying finishConnect only if connection was just established
if (connectExecutor.wasCalled()) {
try {
underlyingConnectorHandler.finishConnect(key);
} catch (IOException ex){
Controller.logger().severe(ex.getMessage());
}
}
}
@Override
public boolean isConnected() {
return underlyingConnectorHandler != null && underlyingConnectorHandler.isConnected();
}
public ConnectorHandler getUnderlyingConnectorHandler() {
return underlyingConnectorHandler;
}
private void notifyCallbackHandlerPseudoConnect() throws ClosedChannelException {
final SelectorHandler underlyingSelectorHandler =
underlyingConnectorHandler.getSelectorHandler();
SelectionKey key = underlyingSelectorHandler.keyFor(underlyingConnectorHandler.getUnderlyingChannel());
// if (key == null) {
// // Register channel on selector
// key = underlyingConnectorHandler.getUnderlyingChannel().
// register(protocolSelector, SelectionKey.OP_CONNECT);
// }
assert key != null;
final NIOContext context = (NIOContext)parentPool.getController().pollContext();
context.setSelectionKey(key);
context.configureOpType(key);
context.setSelectorHandler(underlyingConnectorHandler.getSelectorHandler());
key.attach(new CallbackHandlerSelectionKeyAttachment(callbackHandler));
callbackHandler.onConnect(new IOEvent.DefaultIOEvent(context));
}
@Override
public Future writeToAsyncQueue( ByteBuffer buffer ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( buffer );
}
@Override
public Future writeToAsyncQueue( ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( buffer, callbackHandler );
}
@Override
public Future writeToAsyncQueue( ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( buffer, callbackHandler, writePreProcessor );
}
@Override
public Future writeToAsyncQueue( ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor, ByteBufferCloner cloner ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( buffer, callbackHandler, writePreProcessor, cloner );
}
@Override
public Future writeToAsyncQueue( SocketAddress dstAddress, ByteBuffer buffer ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( dstAddress, buffer );
}
@Override
public Future writeToAsyncQueue( SocketAddress dstAddress, ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( dstAddress, buffer, callbackHandler );
}
@Override
public Future writeToAsyncQueue( SocketAddress dstAddress, ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( dstAddress, buffer, callbackHandler, writePreProcessor );
}
@Override
public Future writeToAsyncQueue( SocketAddress dstAddress, ByteBuffer buffer, AsyncWriteCallbackHandler callbackHandler, AsyncQueueDataProcessor writePreProcessor, ByteBufferCloner cloner ) throws IOException {
return underlyingConnectorHandler.writeToAsyncQueue( dstAddress, buffer, callbackHandler, writePreProcessor, cloner );
}
@Override
public Future readFromAsyncQueue( ByteBuffer buffer, AsyncReadCallbackHandler callbackHandler ) throws IOException {
return underlyingConnectorHandler.readFromAsyncQueue( buffer, callbackHandler );
}
@Override
public Future readFromAsyncQueue( ByteBuffer buffer, AsyncReadCallbackHandler callbackHandler, AsyncReadCondition condition ) throws IOException {
return underlyingConnectorHandler.readFromAsyncQueue( buffer, callbackHandler, condition );
}
@Override
public Future readFromAsyncQueue( ByteBuffer buffer, AsyncReadCallbackHandler callbackHandler, AsyncReadCondition condition, AsyncQueueDataProcessor readPostProcessor ) throws IOException {
return underlyingConnectorHandler.readFromAsyncQueue( buffer, callbackHandler, condition, readPostProcessor );
}
/**
* Class is responsible for execution corresponding
* underlying {@link ConnectorHandler} connect method
*/
private class ConnectExecutor {
private int methodNumber;
private SocketAddress remoteAddress;
private SocketAddress localAddress;
private SelectorHandler selectorHandler;
private CallbackHandler callbackHandler;
private boolean wasCalled;
public void setConnectorHandler(ConnectorHandler connectorHandler) {
underlyingConnectorHandler = connectorHandler;
}
public void setParameters(SocketAddress remoteAddress, CallbackHandler callbackHandler, SelectorHandler selectorHandler) {
setParameters(remoteAddress, null, callbackHandler, selectorHandler);
methodNumber = 1;
}
public void setParameters(SocketAddress remoteAddress, CallbackHandler callbackHandler) {
setParameters(remoteAddress, null, callbackHandler);
methodNumber = 2;
}
public void setParameters(SocketAddress remoteAddress) {
setParameters(remoteAddress, (SocketAddress) null);
methodNumber = 3;
}
public void setParameters(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler,SelectorHandler selectorHandler) {
wasCalled = false;
this.remoteAddress = remoteAddress;
this.localAddress = localAddress;
this.callbackHandler = callbackHandler;
this.selectorHandler = selectorHandler;
methodNumber = 4;
}
public void setParameters(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler) {
setParameters(remoteAddress, localAddress, callbackHandler , null);
methodNumber = 5;
}
public void setParameters(SocketAddress remoteAddress, SocketAddress localAddress) {
setParameters(remoteAddress, localAddress, null);
methodNumber = 6;
}
public boolean wasCalled() {
return wasCalled;
}
public void invokeProtocolConnect() throws IOException {
wasCalled = true;
switch(methodNumber) {
case 1: underlyingConnectorHandler.connect(remoteAddress,
CacheableConnectorHandler.this.callbackHandler,
selectorHandler);
break;
case 2:
case 3: underlyingConnectorHandler.connect(remoteAddress,
CacheableConnectorHandler.this.callbackHandler);
break;
case 4: underlyingConnectorHandler.connect(remoteAddress,
localAddress, CacheableConnectorHandler.this.callbackHandler,
selectorHandler);
break;
case 5:
case 6: underlyingConnectorHandler.connect(remoteAddress,
localAddress, CacheableConnectorHandler.this.callbackHandler);
break;
default: throw new IllegalStateException(
"Can not find appropriate connect method: " + methodNumber);
}
}
}
//---------------------- ContactInfo implementation --------------------------------
private static class CacheableConnectorInfo implements ContactInfo {
private SelectorHandler selectorHandler;
private final CacheableConnectorHandlerPool parentPool;
private final ConnectExecutor connectExecutor;
private final Protocol protocol;
private final SocketAddress targetAddress;
public CacheableConnectorInfo(CacheableConnectorHandlerPool parentPool,
ConnectExecutor connectExecutor,
Protocol protocol, SocketAddress targetAddress) {
this.parentPool = parentPool;
this.connectExecutor = connectExecutor;
this.protocol = protocol;
this.targetAddress = targetAddress;
}
public ConnectorHandler createConnection() throws IOException {
ConnectorHandler connectorHandler =
parentPool.getProtocolConnectorHandlerPool().
acquireConnectorHandler(protocol);
connectExecutor.setConnectorHandler(connectorHandler);
connectExecutor.invokeProtocolConnect();
selectorHandler = connectorHandler.getSelectorHandler();
return connectorHandler;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getClass().getName());
sb.append(" targetAddress: ");
sb.append(targetAddress);
sb.append(" protocol: ");
sb.append(protocol);
sb.append(" hashCode: ");
sb.append(super.hashCode());
return sb.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final CacheableConnectorInfo other = (CacheableConnectorInfo) obj;
if (this.selectorHandler != null && other.selectorHandler != null) {
if (this.selectorHandler != other.selectorHandler &&
!this.selectorHandler.equals(other.selectorHandler)) {
return false;
}
}
if (this.protocol != other.protocol) {
return false;
}
if (this.targetAddress != other.targetAddress &&
(this.targetAddress == null ||
!this.targetAddress.equals(other.targetAddress))) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 47 * hash +
(this.protocol != null ?
this.protocol.hashCode() : 0);
hash = 47 * hash +
(this.targetAddress != null ?
this.targetAddress.hashCode() : 0);
return hash;
}
//----- Override hashCode(), equals() as part of ContactInfo implementation -----------
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy