##### Coverage Report - com.sun.grizzly.DefaultProtocolChain

Classes in this File | Line Coverage | Branch Coverage | Complexity
DefaultProtocolChain |
62 % | 42/68
61 % | 17/28
| 0.0;0
DefaultProtocolChain$EventHandler |
N/A | N/A
N/A | N/A
| 0.0;0
DefaultProtocolChain$Phase |
0 % | 0/1
N/A | N/A
| 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;
40 |  |
41 |  |
     import java.util.ArrayList;
42 |  |
     import java.util.Collection;
43 |  |
     import java.util.HashSet;
44 |  |
     import java.util.List;
45 |  |
     import java.util.logging.Level;
46 |  |
47 |  |
     /**
48 |  |
      * Default ProtocolChain implementation.
49 |  |
      *
50 |  |
      * @author Jeanfrancois Arcand
51 |  |
      */
52 |  |
     public class DefaultProtocolChain implements ProtocolChain, ReinvokeAware {
53 |  |
54 | 0 |
         public enum Phase {EXECUTE, POST_EXECUTE};
55 |  |
56 |  |
         /**
57 |  |
          * The list of ProtocolFilter this chain will invoke.
58 |  |
          */
59 |  |
         protected List<ProtocolFilter> protocolFilters;
60 |  |
61 |  |
         /**
62 |  |
          * The list of {@link EventHandler}s, which will be notified about this
63 |  |
          * {@link ProtocolChain} events
64 |  |
          */
65 |  |
         protected Collection<EventHandler> eventHandlers;
66 |  |
67 |  |
         /**
68 |  |
          * <tt>true</tt> if a pipelined execution is required. A pipelined execution
69 |  |
          * occurs when a ProtocolFilter implementation set the
70 |  |
          * ProtocolFilter.READ_SUCCESS as an attribute to a Context. When this
71 |  |
          * attribute is present, the ProtocolChain will not release the current
72 |  |
          * running Thread and will re-execute all its ProtocolFilter.
73 |  |
          */
74 | 117 |
         protected boolean continousExecution = false;
75 |  |
76 |  |
77 | 117 |
         public DefaultProtocolChain() {
78 | 117 |
             protocolFilters = new ArrayList<ProtocolFilter>();
79 | 117 |
             eventHandlers = new HashSet<EventHandler>();
80 | 117 |
         }
81 |  |
82 |  |
83 |  |
         /**
84 |  |
          * Execute this ProtocolChain.
85 |  |
          * @param ctx {@link Context}
86 |  |
          * @throws java.lang.Exception
87 |  |
          */
88 |  |
         public void execute(Context ctx) throws Exception {
89 | 90801 |
             execute(ctx,0);
90 | 90801 |
         }
91 |  |
92 |  |
93 |  |
         /**
94 |  |
          * Execute this ProtocolChain.
95 |  |
          * @param ctx {@link Context}
96 |  |
          * @param firstFilter The first filter to be invoked.
97 |  |
          * @throws java.lang.Exception
98 |  |
          */
99 |  |
         public void execute(Context ctx, int firstFilter) throws Exception {
100 | 90804 |
             if (protocolFilters.size() != 0){
101 | 90804 |
                 boolean reinvokeChain = true;
102 | 181608 |
                 while (reinvokeChain){
103 | 90804 |
                     int currentPosition = executeProtocolFilter(ctx,firstFilter);
104 | 90804 |
                     reinvokeChain = postExecuteProtocolFilter(currentPosition, ctx);
105 | 90804 |
                 }
106 |  |
             }
107 | 90804 |
         }
108 |  |
109 |  |
         /**
110 |  |
          * Execute the ProtocolFilter.execute method. If a ProtocolFilter.execute
111 |  |
          * return false, avoid invoking the next ProtocolFilter.
112 |  |
          * @param ctx {@link Context}
113 |  |
          * @return position of next {@link ProtocolFilter} to exexute
114 |  |
          */
115 |  |
         protected int executeProtocolFilter(Context ctx) {
116 | 0 |
             return executeProtocolFilter(ctx,0);
117 |  |
         }
118 |  |
119 |  |
120 |  |
         /**
121 |  |
          * Execute the ProtocolFilter.execute method. If a ProtocolFilter.execute
122 |  |
          * return false, avoid invoking the next ProtocolFilter.
123 |  |
          * @param ctx {@link Context}
124 |  |
          * @param firstFilter The first filter position to be invoked.
125 |  |
          * @return position of next {@link ProtocolFilter} to exexute
126 |  |
          */
127 |  |
         protected int executeProtocolFilter(Context ctx, int firstFilter) {
128 |  |
             boolean invokeNext;
129 | 90804 |
             int size = protocolFilters.size();
130 | 90804 |
             int currentPosition = 0;
131 | 90804 |
             ProtocolFilter protocolFilter = null;
132 |  |
133 | 181446 |
             for (int i=firstFilter; i < size; i++) {
134 |  |
                 try {
135 | 181446 |
                     protocolFilter = protocolFilters.get(i);
136 | 181446 |
                     invokeNext = protocolFilter.execute(ctx);
137 | 0 |
                 } catch (Exception ex){
138 | 0 |
                     invokeNext = false;
139 | 0 |
                     i--;
140 | 0 |
                     Controller.logger().log(Level.SEVERE,
141 |  |
                             "ProtocolChain exception",ex);
142 | 0 |
                     notifyException(Phase.EXECUTE, protocolFilter, ex);
143 | 181446 |
                 }
144 |  |
145 | 181446 |
                 currentPosition = i;
146 | 181446 |
                 if ( !invokeNext ) break;
147 |  |
             }
148 | 90804 |
             return currentPosition;
149 |  |
         }
150 |  |
151 |  |
152 |  |
         /**
153 |  |
          * Execute the ProtocolFilter.postExcute.
154 |  |
          * @param currentPosition position in list of {@link ProtocolFilter}s
155 |  |
          * @param ctx {@link Context}
156 |  |
          * @return false, always false
157 |  |
          */
158 |  |
         protected boolean postExecuteProtocolFilter(int currentPosition,Context ctx) {
159 | 90804 |
             boolean invokeNext = true;
160 | 90804 |
             ProtocolFilter tmpHandler = null;
161 | 90804 |
             boolean reinvokeChain = false;
162 | 272245 |
             for (int i = currentPosition; i > -1; i--){
163 |  |
                 try{
164 | 181447 |
                     tmpHandler = protocolFilters.get(i);
165 | 181445 |
                     invokeNext = tmpHandler.postExecute(ctx);
166 | 0 |
                 } catch (Exception ex){
167 | 0 |
                     Controller.logger().log(Level.SEVERE,
168 |  |
                             "ProtocolChain exception",ex);
169 | 0 |
                     notifyException(Phase.POST_EXECUTE, tmpHandler, ex);
170 | 181447 |
                 }
171 | 181447 |
                 if ( !invokeNext ) {
172 | 6 |
                    break;
173 |  |
                 }
174 |  |
             }
175 |  |
176 | 90804 |
             ProtocolChainInstruction postInstruction =
177 |  |
                     (ProtocolChainInstruction) ctx.removeAttribute(
178 |  |
                     PROTOCOL_CHAIN_POST_INSTRUCTION);
179 |  |
180 | 90804 |
             if (postInstruction != null &&
181 |  |
                     postInstruction == ProtocolChainInstruction.REINVOKE) {
182 | 0 |
                 reinvokeChain = true;
183 | 90804 |
             } else if (continousExecution
184 |  |
                 && currentPosition == protocolFilters.size() -1
185 |  |
                 && (Boolean)ctx.removeAttribute(ProtocolFilter.SUCCESSFUL_READ)
186 |  |
                     == Boolean.TRUE) {
187 | 0 |
                 reinvokeChain = true;
188 |  |
             }
189 |  |
190 | 90804 |
             return reinvokeChain;
191 |  |
         }
192 |  |
193 |  |
194 |  |
         /**
195 |  |
          * Remove a ProtocolFilter.
196 |  |
          * @param theFilter the ProtocolFilter to remove
197 |  |
          * @return removed ProtocolFilter
198 |  |
          */
199 |  |
         public boolean removeFilter(ProtocolFilter theFilter) {
200 | 0 |
             return protocolFilters.remove(theFilter);
201 |  |
         }
202 |  |
203 |  |
204 |  |
         /**
205 |  |
          * Add the {@link ProtocolFilter} to this {@link ProtocolChain}
206 |  |
          * @param protocolFilter to add
207 |  |
          * @return
208 |  |
          */
209 |  |
         public boolean addFilter(ProtocolFilter protocolFilter) {
210 | 180 |
             return protocolFilters.add(protocolFilter);
211 |  |
         }
212 |  |
213 |  |
214 |  |
         /**
215 |  |
          * Insert a ProtocolFilter at position pos.
216 |  |
          * @param pos
217 |  |
          * @param protocolFilter
218 |  |
          */
219 |  |
         public void addFilter(int pos, ProtocolFilter protocolFilter){
220 | 0 |
             protocolFilters.add(pos,protocolFilter);
221 | 0 |
         }
222 |  |
223 |  |
224 |  |
         /**
225 |  |
          *Insert a ProtocolFilter at position pos.
226 |  |
          * @param pos - position in this ProtocolChain
227 |  |
          * @param protocolFilter - {@link ProtocolFilter} to insert
228 |  |
          * @return {@link ProtocolFilter} that was set
229 |  |
          */
230 |  |
         public ProtocolFilter setProtocolFilter(int pos,
231 |  |
                 ProtocolFilter protocolFilter) {
232 | 0 |
             return protocolFilters.set(pos,protocolFilter);
233 |  |
         }
234 |  |
235 |  |
236 |  |
         /**
237 |  |
          * Set to <tt>true</tt> if the current {@link Pipeline} can
238 |  |
          * re-execute its ProtocolFilter(s) after a successful execution. Enabling
239 |  |
          * this property is useful for protocol that needs to support pipelined
240 |  |
          * message requests as the ProtocolFilter are automatically re-executed,
241 |  |
          * avoiding the overhead of releasing the current Thread, registering
242 |  |
          * back the SelectionKey to the SelectorHandler and waiting for a new
243 |  |
          * NIO event.
244 |  |
          *
245 |  |
          * Some protocols (like http) can get the http headers in one
246 |  |
          * SocketChannel.read, parse the message and then get the next http message
247 |  |
          * on the second SocketChannel.read(). Not having to release the Thread
248 |  |
          * and re-execute the ProtocolFilter greatly improve performance.
249 |  |
          * @param continousExecution true to enable continuous execution.
250 |  |
          *        (default is false).
251 |  |
          */
252 |  |
         public void setContinuousExecution(boolean continousExecution){
253 | 6 |
             this.continousExecution = continousExecution;
254 | 6 |
             for (ProtocolFilter filter : protocolFilters){
255 | 18 |
                 if (filter instanceof ReinvokeAware){
256 | 0 |
                     ((ReinvokeAware) filter).setContinuousExecution(continousExecution);
257 | 0 |
                     break;
258 |  |
                 }
259 |  |
             }
260 | 6 |
         }
261 |  |
262 |  |
263 |  |
         /**
264 |  |
          * Return <tt>true</tt> if the current {@link Pipeline} can
265 |  |
          * re-execute its ProtocolFilter after a successful execution.
266 |  |
          */
267 |  |
         public boolean isContinuousExecution(){
268 | 0 |
             return continousExecution;
269 |  |
         }
270 |  |
271 |  |
272 |  |
         /**
273 |  |
          * Add the {@link EventHandler}
274 |  |
          * @param eventHandler
275 |  |
          * @return true, if {@link EventHandler} was added, false otherwise
276 |  |
          */
277 |  |
         public boolean addEventHandler(EventHandler eventHandler) {
278 | 0 |
             return eventHandlers.add(eventHandler);
279 |  |
         }
280 |  |
281 |  |
282 |  |
         /**
283 |  |
          * Remove the {@link EventHandler}.
284 |  |
          * @param eventHandler the <code>ProtocolFilter<code> to remove
285 |  |
          * @return true, if {@link EventHandler} was removed, false otherwise
286 |  |
          */
287 |  |
         public boolean removeEventHandler(EventHandler eventHandler) {
288 | 0 |
             return eventHandlers.remove(eventHandler);
289 |  |
         }
290 |  |
291 |  |
         /**
292 |  |
          * Notifies all {@link EventHandler}s about exception, which occured
293 |  |
          * @param phase execution <code>Phase</code>, where exception occured
294 |  |
          * @param filter {@link ProtocolFilter}, where exception occured
295 |  |
          * @param throwable actual exception
296 |  |
          */
297 |  |
         protected void notifyException(Phase phase, ProtocolFilter filter,
298 |  |
                 Throwable throwable) {
299 | 0 |
             for(EventHandler eventHandler : eventHandlers) {
300 |  |
                 try {
301 | 0 |
                     eventHandler.onException(phase, filter, throwable);
302 | 0 |
                 } catch(Exception e) {
303 | 0 |
                     Controller.logger().log(Level.SEVERE,
304 |  |
                             "ProtocolChain notifyException exception", e);
305 |  |
306 | 0 |
                 }
307 |  |
             }
308 | 0 |
         }
309 |  |
310 |  |
         /**
311 |  |
          * Interface, which introduces handler, which will be notified about event,
312 |  |
          * happened on {@link ProtocolChain}
313 |  |
          */
314 |  |
         public interface EventHandler {
315 |  |
             public void onException(Phase phase, ProtocolFilter filter,
316 |  |
                     Throwable throwable);
317 |  |
         }
318 |  |
     }