##### Coverage Report - com.sun.grizzly.filter.ParserProtocolFilter

Classes in this File | Line Coverage | Branch Coverage | Complexity
ParserProtocolFilter |
70 % | 43/61
58 % | 21/36
| 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 |  |
     package com.sun.grizzly.filter;
39 |  |
40 |  |
     import com.sun.grizzly.Context;
41 |  |
     import com.sun.grizzly.Context.AttributeScope;
42 |  |
     import com.sun.grizzly.ProtocolChain;
43 |  |
     import com.sun.grizzly.ProtocolChainInstruction;
44 |  |
     import com.sun.grizzly.ProtocolParser;
45 |  |
     import com.sun.grizzly.util.AttributeHolder;
46 |  |
     import com.sun.grizzly.util.WorkerThread;
47 |  |
     import java.io.IOException;
48 |  |
     import java.nio.ByteBuffer;
49 |  |
     import java.nio.channels.SelectionKey;
50 |  |
51 |  |
     import com.sun.grizzly.util.ThreadAttachment;
52 |  |
     import com.sun.grizzly.util.ThreadAttachment.Mode;
53 |  |
54 |  |
     /**
55 |  |
      * Simple ProtocolFilter implementation which read the available bytes
56 |  |
      * and delegate the decision of reading more bytes or not to a ProtocolParser.
57 |  |
      * The ProtocolParser will decide if more bytes are required before continuing
58 |  |
      * the invokation of the ProtocolChain.
59 |  |
      *
60 |  |
      * @author Jeanfrancois Arcand
61 |  |
      */
62 |  |
     public abstract class ParserProtocolFilter extends ReadFilter {
63 |  |
64 |  |
         /**
65 |  |
          * Should ParserProtocolFilter read the data from channel
66 |  |
          */
67 |  |
         protected boolean isSkipRead;
68 |  |
69 | 2 |
         public ParserProtocolFilter() {
70 | 2 |
         }
71 |  |
72 |  |
         /**
73 |  |
          * Read available bytes and delegate the processing of them to the next
74 |  |
          * ProtocolFilter in the ProtocolChain.
75 |  |
          * @return <tt>true</tt> if the next ProtocolFilter on the ProtocolChain
76 |  |
          * need to be invoked.
77 |  |
          */
78 |  |
         @Override
79 |  |
         public boolean execute(Context ctx) throws IOException {
80 | 2 |
             ProtocolParser parser = null;
81 |  |
82 |  |
             // Remove Parser from Connection related attributes (if it was there)
83 |  |
84 | 2 |
             AttributeHolder connectionAttrs =
85 |  |
                     ctx.getAttributeHolderByScope(AttributeScope.CONNECTION);
86 | 2 |
             if (connectionAttrs != null) {
87 | 1 |
                 parser = (ProtocolParser) connectionAttrs.removeAttribute(ProtocolParser.PARSER);
88 |  |
             }
89 |  |
90 | 2 |
             if (parser == null) {
91 | 2 |
                 parser = (ProtocolParser) ctx.getAttribute(ProtocolParser.PARSER);
92 |  |
93 | 2 |
                 if (parser == null) {
94 | 2 |
                     parser = newProtocolParser();
95 | 2 |
                     ctx.setAttribute(ProtocolParser.PARSER, parser);
96 |  |
                 }
97 |  |
             } else {
98 | 0 |
                 ctx.setAttribute(ProtocolParser.PARSER, parser);
99 |  |
             }
100 |  |
101 | 2 |
             boolean isExpectingMoreData = parser.isExpectingMoreData();
102 | 2 |
             if (isExpectingMoreData || !parser.hasMoreBytesToParse()) {
103 | 2 |
                 if (isExpectingMoreData) {
104 |  |
                     // Saved ByteBuffer was restored. May be we will not need it next time
105 | 0 |
                     ((WorkerThread) Thread.currentThread()).updateAttachment(Mode.ATTRIBUTES_ONLY);
106 |  |
                 }
107 |  |
108 | 2 |
                 boolean continueExecution = isSkipRead || super.execute(ctx);
109 | 2 |
                 WorkerThread workerThread = (WorkerThread) Thread.currentThread();
110 | 2 |
                 ByteBuffer byteBuffer = workerThread.getByteBuffer();
111 | 2 |
                 parser.startBuffer(byteBuffer);
112 | 2 |
                 if (!continueExecution) {
113 | 0 |
                     return continueExecution;
114 |  |
                 }
115 |  |
             }
116 | 2 |
             if (!parser.hasNextMessage()) {
117 | 1 |
                 return false;
118 |  |
             }
119 |  |
120 | 1 |
             return invokeProtocolParser(ctx, parser);
121 |  |
         }
122 |  |
123 |  |
         /**
124 |  |
          * Invoke the {@link ProtocolParser}. If more bytes are required,
125 |  |
          * register the {@link SelectionKey} back to its associated
126 |  |
          * {@link SelectorHandler}
127 |  |
          * @param ctx the Context object.
128 |  |
          * @return <tt>true</tt> if no more bytes are needed.
129 |  |
          */
130 |  |
         protected boolean invokeProtocolParser(Context ctx, ProtocolParser parser) {
131 |  |
132 | 1 |
             if (parser == null) {
133 | 0 |
                 throw new IllegalStateException("ProcotolParser cannot be null");
134 |  |
             }
135 |  |
136 | 1 |
             Object o = parser.getNextMessage();
137 | 1 |
             ctx.setAttribute(ProtocolParser.MESSAGE, o);
138 | 1 |
             return true;
139 |  |
         }
140 |  |
141 |  |
         @Override
142 |  |
         public boolean postExecute(Context context) throws IOException {
143 | 2 |
             ProtocolParser parser = (ProtocolParser) context.getAttribute(ProtocolParser.PARSER);
144 |  |
145 | 2 |
             if (parser == null) {
146 | 0 |
                 return true;
147 |  |
             }
148 |  |
149 | 2 |
             if (parser != null && parser.hasMoreBytesToParse()) {
150 |  |
                 // Need to say that we read successfully since bytes are left
151 | 0 |
                 context.setAttribute(ProtocolChain.PROTOCOL_CHAIN_POST_INSTRUCTION,
152 |  |
                         ProtocolChainInstruction.REINVOKE);
153 | 0 |
                 return true;
154 |  |
             }
155 |  |
156 | 2 |
             if (context.getKeyRegistrationState() !=
157 |  |
                     Context.KeyRegistrationState.CANCEL) {
158 |  |
159 | 2 |
                 SelectionKey key = context.getSelectionKey();
160 | 2 |
                 if (parser.isExpectingMoreData()) {
161 | 1 |
                     if (parser.releaseBuffer()) {
162 | 0 |
                         saveParser(key, parser);
163 |  |
                     }
164 |  |
165 | 1 |
                     saveByteBuffer(key);
166 |  |
167 |  |
                     // Register to get more bytes.
168 | 1 |
                     context.getSelectorHandler().register(key, SelectionKey.OP_READ);
169 | 1 |
                     return false;
170 |  |
                 }
171 |  |
172 | 1 |
                 if (parser.releaseBuffer()) {
173 | 0 |
                     saveParser(key, parser);
174 |  |
                 }
175 | 1 |
             } else {
176 | 0 |
                 parser.releaseBuffer();
177 |  |
             }
178 |  |
179 | 1 |
             return super.postExecute(context);
180 |  |
         }
181 |  |
182 |  |
         /**
183 |  |
          * Return a new or cached ProtocolParser instance.
184 |  |
          */
185 |  |
         public abstract ProtocolParser newProtocolParser();
186 |  |
187 |  |
         private void saveByteBuffer(SelectionKey key) {
188 | 1 |
             WorkerThread workerThread = (WorkerThread) Thread.currentThread();
189 |  |
             // Detach the current Thread data.
190 | 1 |
             ThreadAttachment threadAttachment =
191 |  |
                     workerThread.updateAttachment(Mode.BYTE_BUFFER);
192 |  |
193 |  |
             // Attach it to the SelectionKey so the it can be resumed latter.
194 | 1 |
             key.attach(threadAttachment);
195 | 1 |
         }
196 |  |
197 |  |
         private void saveParser(SelectionKey key, ProtocolParser parser) {
198 | 0 |
             WorkerThread workerThread = (WorkerThread) Thread.currentThread();
199 |  |
             // Detach the current Thread data.
200 | 0 |
             ThreadAttachment threadAttachment = workerThread.getAttachment();
201 | 0 |
             threadAttachment.setAttribute(ProtocolParser.PARSER, parser);
202 |  |
             // Attach it to the SelectionKey so the it can be resumed latter.
203 | 0 |
             key.attach(threadAttachment);
204 | 0 |
         }
205 |  |
206 |  |
         /**
207 |  |
          * Method returns true, if this Filter perform channel read operation on
208 |  |
          * execute, or false - Filter assumes the data was read by previous Filters in
209 |  |
          * a chain.
210 |  |
          *
211 |  |
          * @return true, if Filter will perform channel read operation on execute.
212 |  |
          * False - Filter assumes the data was read by previous Filters in a chain.
213 |  |
          */
214 |  |
         protected boolean isSkipRead() {
215 | 0 |
             return isSkipRead;
216 |  |
         }
217 |  |
218 |  |
         /**
219 |  |
          * Method set if this Filter should perform channel read operation on
220 |  |
          * execute, or should assumes the data was read by previous Filters in
221 |  |
          * a chain.
222 |  |
          *
223 |  |
          * @param isSkipRead If isSkipRead is true, this Filter will perform
224 |  |
          * channel read operation on execute. If false - Filter assumes the data
225 |  |
          * was read by previous Filters in a chain.
226 |  |
          */
227 |  |
         protected void setSkipRead(boolean isSkipRead) {
228 | 0 |
             this.isSkipRead = isSkipRead;
229 | 0 |
         }
230 |  |
     }