##### Coverage Report - com.sun.grizzly.connectioncache.client.CacheableConnectorHandler

Classes in this File | Line Coverage | Branch Coverage | Complexity
CacheableConnectorHandler |
47 % | 43/92
25 % | 7/28
| 0.0;0
CacheableConnectorHandler$1 |
0 % | 0/7
N/A | N/A
| 0.0;0
CacheableConnectorHandler$ConnectExecutor |
58 % | 22/38
14 % | 1/7
| 0.0;0

1 |  |
     /*
2 |  |
      *
3 |  |
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 |  |
      *
5 |  |
      * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
6 |  |
      *
7 |  |
      * The contents of this file are subject to the terms of either the GNU
8 |  |
      * General Public License Version 2 only ("GPL") or the Common Development
9 |  |
      * and Distribution License("CDDL") (collectively, the "License").  You
10 |  |
      * may not use this file except in compliance with the License. You can obtain
11 |  |
      * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
12 |  |
      * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
13 |  |
      * language governing permissions and limitations under the License.
14 |  |
      *
15 |  |
      * When distributing the software, include this License Header Notice in each
16 |  |
      * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
17 |  |
      * Sun designates this particular file as subject to the "Classpath" exception
18 |  |
      * as provided by Sun in the GPL Version 2 section of the License file that
19 |  |
      * accompanied this code.  If applicable, add the following below the License
20 |  |
      * Header, with the fields enclosed by brackets [] replaced by your own
21 |  |
      * identifying information: "Portions Copyrighted [year]
22 |  |
      * [name of copyright owner]"
23 |  |
      *
24 |  |
      * Contributor(s):
25 |  |
      *
26 |  |
      * If you wish your version of this file to be governed by only the CDDL or
27 |  |
      * only the GPL Version 2, indicate your decision by adding "[Contributor]
28 |  |
      * elects to include this software in this distribution under the [CDDL or GPL
29 |  |
      * Version 2] license."  If you don't indicate a single choice of license, a
30 |  |
      * recipient has the option to distribute your version of this file under
31 |  |
      * either the CDDL, the GPL Version 2 or to extend the choice of license to
32 |  |
      * its licensees as provided above.  However, if you add GPL Version 2 code
33 |  |
      * and therefore, elected the GPL Version 2 license, then the option applies
34 |  |
      * only if the new code is made subject to such option by the copyright
35 |  |
      * holder.
36 |  |
      *
37 |  |
      */
38 |  |
39 |  |
     package com.sun.grizzly.connectioncache.client;
40 |  |
41 |  |
     import com.sun.grizzly.CallbackHandler;
42 |  |
     import com.sun.grizzly.ConnectorHandler;
43 |  |
     import com.sun.grizzly.Context;
44 |  |
     import com.sun.grizzly.Controller;
45 |  |
     import com.sun.grizzly.Controller.Protocol;
46 |  |
     import com.sun.grizzly.IOEvent;
47 |  |
     import com.sun.grizzly.SelectorHandler;
48 |  |
     import com.sun.grizzly.connectioncache.spi.transport.ContactInfo;
49 |  |
     import java.io.IOException;
50 |  |
     import java.net.SocketAddress;
51 |  |
     import java.nio.ByteBuffer;
52 |  |
     import java.nio.channels.ClosedChannelException;
53 |  |
     import java.nio.channels.SelectableChannel;
54 |  |
     import java.nio.channels.SelectionKey;
55 |  |
     import java.nio.channels.Selector;
56 |  |
57 |  |
     /**
58 |  |
      * Extended implementation of the DefaultSelectionKeyHandler with
59 |  |
      * ConnectionManagement integrated in it
60 |  |
      *
61 |  |
      * @author Alexey Stashok
62 |  |
      */
63 | 2 |
     public class CacheableConnectorHandler implements ConnectorHandler<SelectorHandler, CallbackHandler>,
64 |  |
             ContactInfo<ConnectorHandler>, CallbackHandler {
65 |  |
         private SocketAddress targetAddress;
66 |  |
         private Protocol protocol;
67 |  |
         private SelectorHandler selectorHandler;
68 |  |
69 |  |
         private CacheableConnectorHandlerPool parentPool;
70 |  |
         private ConnectorHandler underlyingConnectorHandler;
71 |  |
         private CallbackHandler underlyingCallbackHandler;
72 |  |
73 |  |
         private ConnectExecutor connectExecutor;
74 |  |
75 | 1 |
         public CacheableConnectorHandler(CacheableConnectorHandlerPool parentPool) {
76 | 1 |
             this.parentPool = parentPool;
77 | 1 |
             connectExecutor = new ConnectExecutor();
78 | 1 |
         }
79 |  |
80 |  |
         void setProtocol(Protocol protocol) {
81 | 10 |
             this.protocol = protocol;
82 | 10 |
         }
83 |  |
84 |  |
         public Protocol protocol() {
85 | 0 |
             return protocol;
86 |  |
         }
87 |  |
88 |  |
         // connect method #1
89 |  |
         public void connect(SocketAddress remoteAddress, CallbackHandler callbackHandler, SelectorHandler selectorHandler) throws IOException {
90 | 0 |
             connectExecutor.setParameters(remoteAddress, callbackHandler, selectorHandler);
91 | 0 |
             doConnect(remoteAddress);
92 | 0 |
         }
93 |  |
94 |  |
         // connect method #2
95 |  |
         public void connect(SocketAddress remoteAddress, CallbackHandler callbackHandler) throws IOException {
96 | 10 |
             connectExecutor.setParameters(remoteAddress, callbackHandler);
97 | 10 |
             doConnect(remoteAddress);
98 | 10 |
         }
99 |  |
100 |  |
         // connect method #3
101 |  |
         public void connect(SocketAddress remoteAddress) throws IOException {
102 | 0 |
             connectExecutor.setParameters(remoteAddress);
103 | 0 |
             doConnect(remoteAddress);
104 | 0 |
         }
105 |  |
106 |  |
         // connect method #4
107 |  |
         public void connect(SocketAddress remoteAddress, SocketAddress localAddress,
108 |  |
                 CallbackHandler callbackHandler, SelectorHandler selectorHandler) throws IOException {
109 | 0 |
             connectExecutor.setParameters(remoteAddress, localAddress, callbackHandler, selectorHandler);
110 | 0 |
             doConnect(remoteAddress);
111 | 0 |
         }
112 |  |
113 |  |
         // connect method #5
114 |  |
         public void connect(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler) throws IOException {
115 | 0 |
             connectExecutor.setParameters(remoteAddress, localAddress, callbackHandler);
116 | 0 |
             doConnect(remoteAddress);
117 | 0 |
         }
118 |  |
119 |  |
         // connect method #6
120 |  |
         public void connect(SocketAddress remoteAddress, SocketAddress localAddress) throws IOException {
121 | 0 |
             connectExecutor.setParameters(remoteAddress, localAddress);
122 | 0 |
             doConnect(remoteAddress);
123 | 0 |
         }
124 |  |
125 |  |
126 |  |
         /**
127 |  |
          * Releases underlying connection, which means it could be reused for writing
128 |  |
          * by other <code>CacheableConnectorHandler</code>, however this
129 |  |
          * <code>CacheableConnectorHandler</code> will be still interested in getting
130 |  |
          * expectedResponseCount responses on it.
131 |  |
          *
132 |  |
          * @param expectedResponseCount number of reponses expected on the connection
133 |  |
          */
134 |  |
         public void release(int expectedResponseCount) {
135 | 0 |
             parentPool.getOutboundConnectionCache().release(underlyingConnectorHandler, expectedResponseCount);
136 | 0 |
         }
137 |  |
138 |  |
         /**
139 |  |
          * Notifies connection cache, that response was received. And connection cache
140 |  |
          * could decrease expected response counter by 1
141 |  |
          */
142 |  |
         public void responseReceived() {
143 | 0 |
             parentPool.getOutboundConnectionCache().responseReceived(underlyingConnectorHandler);
144 | 0 |
         }
145 |  |
146 |  |
         /**
147 |  |
          * @param targetAddress target connection address
148 |  |
          * @throws java.io.IOException if IO error happened
149 |  |
          */
150 |  |
         private void doConnect(SocketAddress targetAddress) throws IOException {
151 | 10 |
             this.targetAddress = targetAddress;
152 | 10 |
             selectorHandler = connectExecutor.selectorHandler;
153 | 10 |
             underlyingCallbackHandler = connectExecutor.callbackHandler;
154 | 10 |
             underlyingConnectorHandler = parentPool.
155 |  |
                     getOutboundConnectionCache().get(this, parentPool.getConnectionFinder());
156 |  |
157 |  |
             /* check whether NEW connection was created, or taken from cache */
158 | 10 |
             if (!connectExecutor.wasCalled()) { // if taken from cache
159 |  |
                 //if connection is taken from cache - explicitly notify callback handler
160 | 9 |
                 underlyingConnectorHandler.setCallbackHandler(this);
161 | 9 |
                 notifyCallbackHandlerPseudoConnect();
162 |  |
             }
163 | 10 |
         }
164 |  |
165 |  |
166 |  |
         public void close() throws IOException {
167 | 10 |
             parentPool.getOutboundConnectionCache().release(underlyingConnectorHandler, 0);
168 | 10 |
         }
169 |  |
170 |  |
         public long read(ByteBuffer byteBuffer, boolean blocking) throws IOException {
171 | 1000 |
             return underlyingConnectorHandler.read(byteBuffer, blocking);
172 |  |
         }
173 |  |
174 |  |
         public long write(ByteBuffer byteBuffer, boolean blocking) throws IOException {
175 | 1000 |
             return underlyingConnectorHandler.write(byteBuffer, blocking);
176 |  |
         }
177 |  |
178 |  |
         public void finishConnect(SelectionKey key) {
179 |  |
             // Call underlying finishConnect only if connection was just established
180 | 10 |
             if (connectExecutor.wasCalled()) {
181 |  |
                 try{
182 | 1 |
                     underlyingConnectorHandler.finishConnect(key);
183 | 0 |
                 } catch (IOException ex){
184 | 0 |
                     Controller.logger().severe(ex.getMessage());
185 | 1 |
                 }
186 |  |
             }
187 | 10 |
         }
188 |  |
189 |  |
         public void setController(Controller controller) {
190 | 0 |
             underlyingConnectorHandler.setController(controller);
191 | 0 |
         }
192 |  |
193 |  |
         public Controller getController() {
194 | 0 |
             return underlyingConnectorHandler.getController();
195 |  |
         }
196 |  |
197 |  |
         public SelectableChannel getUnderlyingChannel() {
198 | 0 |
             return underlyingConnectorHandler.getUnderlyingChannel();
199 |  |
         }
200 |  |
201 |  |
         public CallbackHandler getCallbackHandler() {
202 | 0 |
             return underlyingConnectorHandler.getCallbackHandler();
203 |  |
         }
204 |  |
205 |  |
         public void setCallbackHandler(CallbackHandler callbackHandler) {
206 | 0 |
             underlyingConnectorHandler.setCallbackHandler(callbackHandler);
207 | 0 |
         }
208 |  |
209 |  |
         public SelectorHandler getSelectorHandler() {
210 | 0 |
             return underlyingConnectorHandler.getSelectorHandler();
211 |  |
         }
212 |  |
213 |  |
214 |  |
         //---------------------- ContactInfo implementation --------------------------------
215 |  |
         public ConnectorHandler createConnection() throws IOException {
216 | 1 |
             underlyingConnectorHandler = parentPool.getProtocolConnectorHandlerPool().acquireConnectorHandler(protocol);
217 |  |
218 | 1 |
             connectExecutor.setConnectorHandler(underlyingConnectorHandler);
219 | 1 |
             connectExecutor.invokeProtocolConnect();
220 | 1 |
             return underlyingConnectorHandler;
221 |  |
         }
222 |  |
223 |  |
         @Override
224 |  |
         public String toString() {
225 | 0 |
             StringBuffer sb = new StringBuffer();
226 | 0 |
             sb.append(getClass().getName());
227 | 0 |
             sb.append(" targetAddress: ");
228 | 0 |
             sb.append(targetAddress);
229 | 0 |
             sb.append(" protocol: ");
230 | 0 |
             sb.append(protocol);
231 | 0 |
             sb.append(" hashCode: ");
232 | 0 |
             sb.append(super.hashCode());
233 | 0 |
             return sb.toString();
234 |  |
         }
235 |  |
236 |  |
         //----- Override hashCode(), equals() as part of ContactInfo implementation -----------
237 |  |
         @Override
238 |  |
         public int hashCode() {
239 | 11 |
             return targetAddress.hashCode() ^ protocol.hashCode();
240 |  |
         }
241 |  |
242 |  |
         @Override
243 |  |
         public boolean equals(Object o) {
244 | 0 |
             if (o instanceof CacheableConnectorHandler) {
245 | 0 |
                 CacheableConnectorHandler handler = (CacheableConnectorHandler) o;
246 | 0 |
                 if (selectorHandler == null || handler.selectorHandler == null) {
247 | 0 |
                     return targetAddress.equals(handler.targetAddress) &&
248 |  |
                             protocol.equals(handler.protocol);
249 |  |
                 } else {
250 | 0 |
                     return targetAddress.equals(handler.targetAddress) &&
251 |  |
                             protocol.equals(handler.protocol) &&
252 |  |
                             selectorHandler == handler.selectorHandler;
253 |  |
                 }
254 |  |
             }
255 |  |
256 | 0 |
             return false;
257 |  |
         }
258 |  |
259 |  |
260 |  |
         private void notifyCallbackHandlerPseudoConnect() throws ClosedChannelException {
261 | 9 |
             Selector protocolSelector = underlyingConnectorHandler.getSelectorHandler().getSelector();
262 | 9 |
             SelectionKey key = underlyingConnectorHandler.getUnderlyingChannel().keyFor(protocolSelector);
263 | 9 |
             if (key == null) {
264 |  |
                 // Register channel on selector
265 | 0 |
                 key = underlyingConnectorHandler.getUnderlyingChannel().
266 |  |
                         register(protocolSelector, SelectionKey.OP_CONNECT);
267 |  |
             }
268 |  |
269 | 9 |
             assert key != null;
270 |  |
271 | 9 |
             final Context context = parentPool.getController().pollContext(key);
272 | 9 |
             onConnect(new IOEvent.DefaultIOEvent<Context>(context));
273 | 9 |
         }
274 |  |
275 |  |
         //---------------------- CallbackHandler implementation --------------------------------
276 |  |
         public void onConnect(IOEvent ioEvent) {
277 | 10 |
             if (underlyingCallbackHandler == null) {
278 | 0 |
                 underlyingCallbackHandler = new CallbackHandler<Context>(){
279 |  |
                     public void onConnect(IOEvent<Context> ioEvent) {
280 | 0 |
                         SelectionKey key = ioEvent.attachment().getSelectionKey();
281 | 0 |
                         finishConnect(key);
282 | 0 |
                         getController().registerKey(key,SelectionKey.OP_WRITE,
283 |  |
                                 protocol);
284 | 0 |
                     }
285 | 0 |
                     public void onRead(IOEvent<Context> ioEvent) {}
286 | 0 |
                     public void onWrite(IOEvent<Context> ioEvent) {}
287 |  |
                 };
288 |  |
             }
289 |  |
290 | 10 |
             underlyingCallbackHandler.onConnect(ioEvent);
291 | 10 |
         }
292 |  |
293 |  |
         public void onRead(IOEvent ioEvent) {
294 | 897 |
             underlyingCallbackHandler.onRead(ioEvent);
295 | 897 |
         }
296 |  |
297 |  |
         public void onWrite(IOEvent ioEvent) {
298 | 0 |
             underlyingCallbackHandler.onWrite(ioEvent);
299 | 0 |
         }
300 |  |
301 |  |
         /**
302 |  |
          * Class is responsible for execution corresponding
303 |  |
          * underlying {@link ConnectorHandler} connect method
304 |  |
          */
305 | 22 |
         private class ConnectExecutor {
306 |  |
             private int methodNumber;
307 |  |
             private ConnectorHandler connectorHandler;
308 |  |
             private SocketAddress remoteAddress;
309 |  |
             private SocketAddress localAddress;
310 |  |
             private SelectorHandler selectorHandler;
311 |  |
             private CallbackHandler callbackHandler;
312 |  |
             private boolean wasCalled;
313 |  |
314 |  |
             public void setConnectorHandler(ConnectorHandler connectorHandler) {
315 | 1 |
                 this.connectorHandler = connectorHandler;
316 | 1 |
             }
317 |  |
318 |  |
             public void setParameters(SocketAddress remoteAddress, CallbackHandler callbackHandler, SelectorHandler selectorHandler) {
319 | 0 |
                 setParameters(remoteAddress, null, callbackHandler, selectorHandler);
320 | 0 |
                 methodNumber = 1;
321 | 0 |
             }
322 |  |
323 |  |
             public void setParameters(SocketAddress remoteAddress, CallbackHandler callbackHandler) {
324 | 10 |
                 setParameters(remoteAddress, null, callbackHandler);
325 | 10 |
                 methodNumber = 2;
326 | 10 |
             }
327 |  |
328 |  |
             public void setParameters(SocketAddress remoteAddress) {
329 | 0 |
                 setParameters(remoteAddress, (SocketAddress) null);
330 | 0 |
                 methodNumber = 3;
331 | 0 |
             }
332 |  |
333 |  |
             public void setParameters(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler,SelectorHandler selectorHandler) {
334 | 10 |
                 wasCalled = false;
335 | 10 |
                 this.remoteAddress = remoteAddress;
336 | 10 |
                 this.localAddress = localAddress;
337 | 10 |
                 this.callbackHandler = callbackHandler;
338 | 10 |
                 this.selectorHandler = selectorHandler;
339 | 10 |
                 methodNumber = 4;
340 | 10 |
             }
341 |  |
342 |  |
             public void setParameters(SocketAddress remoteAddress, SocketAddress localAddress, CallbackHandler callbackHandler) {
343 | 10 |
                 setParameters(remoteAddress, localAddress, callbackHandler , null);
344 | 10 |
                 methodNumber = 5;
345 | 10 |
             }
346 |  |
347 |  |
             public void setParameters(SocketAddress remoteAddress, SocketAddress localAddress) {
348 | 0 |
                 setParameters(remoteAddress, localAddress, null);
349 | 0 |
                 methodNumber = 6;
350 | 0 |
             }
351 |  |
352 |  |
             public boolean wasCalled() {
353 | 20 |
                 return wasCalled;
354 |  |
             }
355 |  |
356 |  |
             public void invokeProtocolConnect() throws IOException {
357 | 1 |
                 wasCalled = true;
358 | 1 |
                 switch(methodNumber) {
359 | 0 |
                 case 1: connectorHandler.connect(remoteAddress, CacheableConnectorHandler.this, selectorHandler);
360 | 0 |
                 break;
361 |  |
                 case 2:
362 | 1 |
                 case 3: connectorHandler.connect(remoteAddress, CacheableConnectorHandler.this);
363 | 1 |
                 break;
364 | 0 |
                 case 4: connectorHandler.connect(remoteAddress, localAddress, CacheableConnectorHandler.this, selectorHandler);
365 | 0 |
                 break;
366 |  |
                 case 5:
367 | 0 |
                 case 6: connectorHandler.connect(remoteAddress, localAddress, CacheableConnectorHandler.this);
368 | 0 |
                 break;
369 | 0 |
                 default: throw new IllegalStateException("Can not find appropriate connect method: " + methodNumber);
370 |  |
                 }
371 | 1 |
             }
372 |  |
         }
373 |  |
     }