Hi.
I tried to test com.sun.grizzly.connectioncache.client.CacheableConnectorHandlerPool with com.sun.grizzly.DefaultCallbackHandler, but I had some problems.
Here is simple test code.
-----
[init part]
Controller controller = new Controller();
ConnectorHandlerPool cacheableHandlerPool = new CacheableConnectorHandlerPool( controller, 100, 10, 1 );
controller.setConnectorHandlerPool( cacheableHandlerPool );
TCPSelectorHandler tcpSelectorHandler = new TCPSelectorHandler();
tcpSelectorHandler.setPort( myPort );
tcpSelectorHandler.setSelectionKeyHandler( new DefaultSelectionKeyHandler() );
controller.addSelectorHandler( tcpSelectorHandler );
...
[send part]
ConnectorHandler connectorHandler;
connectorHandler = controller.acquireConnectorHandler( Controller.Protocol.TCP );
..
connectorHandler.connect( remoteAddress, localAddress, new DefaultCallbackHandler( connectorHandler ) );
OutputWrite.flushChannel( connectorHandler.getUnderlyingChannel(), appMessage, timeout );
...
-----
Here is result.
-----
java.lang.IllegalStateException: Invalid Response State. SocketChannel cannot be null.
at com.sun.grizzly.util.OutputWriter.flushChannel(OutputWriter.java:94)
at SimpleTestServer.sendTest(SimpleTestServer.java:134)
at SimpleTestServer.main(SimpleTestServer.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:623)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
java.lang.NullPointerException
at com.sun.grizzly.connectioncache.client.CacheableConnectorHandler.notifyCallbackHandlerPseudoConnect(CacheableConnectorHandler.java:222)
at com.sun.grizzly.connectioncache.client.CacheableConnectorHandler.doConnect(CacheableConnectorHandler.java:164)
at com.sun.grizzly.connectioncache.client.CacheableConnectorHandler.connect(CacheableConnectorHandler.java:117)
at SimpleTestServer.sendTest(SimpleTestServer.java:132)
at SimpleTestServer.main(SimpleTestServer.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:623)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
-----
Here is the NPE's line.
In CacheableConnectorHandler.java
-----
private voide notifyCallbackHandlerPseudoConnect() throws ClosedChannelException {
...
SelectionKey key = underlyingConnectorHandler.getUnderlyingChannel().keyFor( protocolSelector );
...
}
I think that ConnectorHandler's socketChannel can be null if unexpected exceptions are occurred in CallbackHandler. ex) if an error was occurred before calling ConnectorHandler#finishConnect(SelectionKey key)
So I think that graceful handling of NPE and more check logic are needed about underlyingConnectorHandler.getUnderlyingChannel().
And I reviewed why this error had been occurred for a while.
When I inserted some test code for debugging, the following error was occurred.
-----
java.lang.ClassCastException: com.sun.grizzly.connectioncache.client.CacheableConnectorHandler cannot be cast to com.sun.grizzly.TCPConnectorHandler
at com.sun.grizzly.DefaultCallbackHandler.onConnect(DefaultCallbackHandler.java:128)
at com.sun.grizzly.connectioncache.client.CacheableConnectorHandler.onConnect(CacheableConnectorHandler.java:250)
at com.sun.grizzly.CallbackHandlerContextTask.doCall(CallbackHandlerContextTask.java:68)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:717)
-----
Here is DefaultCallbackHandler#onConnect(IOEvent<Context> ioEvent);
In DefaultCallbackHandler.java
-----
public void onConnect( IOEvent<Context> ioEvent ) {
SelectionKey key = ioEvent.attachment().getSelectionKey();
if( ioEvent.attachment().getProtocol() == Controller.Protocol.TCP ) {
((TCPConnectorHandler)connectorHandler).setUnderlyingChannel((SocketChannel)key.channel());
} else if( ioEvent.attachment().getProtocol() == Controller.Protocol.TLS) {
((SSLConnectorHandler)connectorHandler).setUnderlyingChannel((SocketChannel)key.channel());
}
try {
connectorHandler.finishConnect(key);
...
}
...
}
-----
I think that above calling setUnderlyingChannel() is redundant because both TCPConnectorHandler#finishConnect() and SSLConnectorHandler#finishConnect() already assign socketChannel key's channel.
Of course, it maybe has no problem if I don't use DefaultCallbackHandler.
But I hope that above reduntant code could be removed and I am curious to know if my use and point have any faults.
Please give me advice.
Thanks.
--
Bongjae Chang