Coverage Report - com.sun.grizzly.DefaultProtocolChain
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultProtocolChain
62 %
42/68
61 %
17/28
0
DefaultProtocolChain$EventHandler
N/A
N/A
0
DefaultProtocolChain$Phase
0 %
0/1
N/A
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  
 }