Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
Utils |
|
| 11.333333333333334;11,333 |
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.util; | |
40 | ||
41 | import java.io.IOException; | |
42 | import java.nio.ByteBuffer; | |
43 | import java.nio.channels.ReadableByteChannel; | |
44 | import java.nio.channels.SelectableChannel; | |
45 | import java.nio.channels.SelectionKey; | |
46 | import java.nio.channels.Selector; | |
47 | ||
48 | /** | |
49 | * Class contains set of useful operations commonly used in the framework | |
50 | * | |
51 | * @author Alexey Stashok | |
52 | * @author Jean-Francois Arcand | |
53 | */ | |
54 | 0 | public class Utils { |
55 | /** | |
56 | * Character translation tables. | |
57 | */ | |
58 | 1 | private static final byte[] toLower = new byte[256]; |
59 | ||
60 | /** | |
61 | * Initialize character translation and type tables. | |
62 | */ | |
63 | static { | |
64 | 257 | for (int i = 0; i < 256; i++) { |
65 | 256 | toLower[i] = (byte)i; |
66 | } | |
67 | ||
68 | 27 | for (int lc = 'a'; lc <= 'z'; lc++) { |
69 | 26 | int uc = lc + 'A' - 'a'; |
70 | 26 | toLower[uc] = (byte)lc; |
71 | } | |
72 | 1 | } |
73 | ||
74 | ||
75 | /** | |
76 | * Method reads data from {@link SelectableChannel} to | |
77 | * {@link ByteBuffer}. If data is not immediately available - channel | |
78 | * will be reregistered on temporary {@link Selector} and wait maximum | |
79 | * readTimeout milliseconds for data. | |
80 | * | |
81 | * @param channel {@link SelectableChannel} to read data from | |
82 | * @param byteBuffer {@link ByteBuffer} to store read data to | |
83 | * @param readTimeout maximum time in millis operation will wait for | |
84 | * incoming data | |
85 | * | |
86 | * @return number of bytes were read | |
87 | * @throws <code>IOException</code> if any error was occured during read | |
88 | */ | |
89 | public static int readWithTemporarySelector(SelectableChannel channel, | |
90 | ByteBuffer byteBuffer, long readTimeout) throws IOException { | |
91 | 1111 | int count = 1; |
92 | 1111 | int byteRead = 0; |
93 | 1111 | int preReadInputBBPos = byteBuffer.position(); |
94 | 1111 | Selector readSelector = null; |
95 | 1111 | SelectionKey tmpKey = null; |
96 | ||
97 | try { | |
98 | 1111 | ReadableByteChannel readableChannel = (ReadableByteChannel) channel; |
99 | 2571 | while (count > 0){ |
100 | 1461 | count = readableChannel.read(byteBuffer); |
101 | 1460 | if ( count > -1 ) |
102 | 1459 | byteRead += count; |
103 | else | |
104 | 1 | byteRead = count; |
105 | } | |
106 | ||
107 | 1110 | if (byteRead == 0 && byteBuffer.position() == preReadInputBBPos) { |
108 | 759 | readSelector = SelectorFactory.getSelector(); |
109 | ||
110 | 759 | if ( readSelector == null ){ |
111 | 0 | return 0; |
112 | } | |
113 | 759 | count = 1; |
114 | ||
115 | 759 | tmpKey = channel.register(readSelector, SelectionKey.OP_READ); |
116 | 759 | tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ); |
117 | 759 | int code = readSelector.select(readTimeout); |
118 | 759 | tmpKey.interestOps( |
119 | tmpKey.interestOps() & (~SelectionKey.OP_READ)); | |
120 | ||
121 | 759 | if ( code == 0 ){ |
122 | 0 | return 0; // Return on the main Selector and try again. |
123 | } | |
124 | ||
125 | 2302 | while (count > 0){ |
126 | 1543 | count = readableChannel.read(byteBuffer); |
127 | 1543 | if ( count > -1 ) |
128 | 1543 | byteRead += count; |
129 | else | |
130 | 0 | byteRead = count; |
131 | } | |
132 | 759 | } else if (byteRead == 0 && byteBuffer.position() != preReadInputBBPos) { |
133 | 0 | byteRead += (byteBuffer.position() - preReadInputBBPos); |
134 | } | |
135 | } finally { | |
136 | 1111 | if (tmpKey != null) |
137 | 759 | tmpKey.cancel(); |
138 | ||
139 | 1111 | if ( readSelector != null) { |
140 | // Bug 6403933 | |
141 | 759 | SelectorFactory.selectNowAndReturnSelector(readSelector); |
142 | } | |
143 | } | |
144 | ||
145 | 1110 | return byteRead; |
146 | } | |
147 | ||
148 | ||
149 | /** | |
150 | * Return the bytes contained between the startByte and the endByte. The ByteBuffer | |
151 | * will be left in the state it was before invoking that method, meaning | |
152 | * its position and limit will be the same. | |
153 | * | |
154 | * @param byteBuffer The bytes. | |
155 | * @param startByte the first byte to look for | |
156 | * @param endByte the second byte to look for | |
157 | * @return The byte[] contained between startByte and endByte | |
158 | */ | |
159 | public static byte[] extractBytes(ByteBuffer byteBuffer, | |
160 | byte startByte, byte endByte) throws IOException{ | |
161 | ||
162 | 0 | int curPosition = byteBuffer.position(); |
163 | 0 | int curLimit = byteBuffer.limit(); |
164 | ||
165 | 0 | if (byteBuffer.position() == 0){ |
166 | 0 | throw new IllegalStateException("Invalid state"); |
167 | } | |
168 | ||
169 | 0 | byteBuffer.position(0); |
170 | 0 | byteBuffer.limit(curPosition); |
171 | 0 | int state =0; |
172 | 0 | int start =0; |
173 | 0 | int end = 0; |
174 | try { | |
175 | byte c; | |
176 | ||
177 | // Rule b - try to determine the context-root | |
178 | 0 | while(byteBuffer.hasRemaining()) { |
179 | 0 | c = byteBuffer.get(); |
180 | 0 | switch(state) { |
181 | case 0: // Search for first ' ' | |
182 | 0 | if (c == startByte){ |
183 | 0 | state = 1; |
184 | 0 | start = byteBuffer.position(); |
185 | } | |
186 | break; | |
187 | case 1: | |
188 | 0 | if (c == endByte){ |
189 | 0 | end = byteBuffer.position(); |
190 | 0 | byte[] bytes = new byte[end - start]; |
191 | 0 | byteBuffer.position(start); |
192 | 0 | byteBuffer.limit(end); |
193 | 0 | byteBuffer.get(bytes); |
194 | 0 | return bytes; |
195 | } | |
196 | break; | |
197 | default: | |
198 | 0 | throw new IllegalArgumentException("Unexpected state"); |
199 | } | |
200 | } | |
201 | 0 | throw new IllegalStateException("Unexpected state"); |
202 | } finally { | |
203 | 0 | byteBuffer.limit(curLimit); |
204 | 0 | byteBuffer.position(curPosition); |
205 | } | |
206 | } | |
207 | ||
208 | ||
209 | ||
210 | /** | |
211 | * Specialized utility method: find a sequence of lower case bytes inside | |
212 | * a ByteBuffer. | |
213 | */ | |
214 | public static int findBytes(ByteBuffer byteBuffer, byte[] b) { | |
215 | 9 | int curPosition = byteBuffer.position(); |
216 | 9 | int curLimit = byteBuffer.limit(); |
217 | ||
218 | 9 | if (byteBuffer.position() == 0){ |
219 | 0 | throw new IllegalStateException("Invalid state"); |
220 | } | |
221 | ||
222 | 9 | byteBuffer.position(0); |
223 | 9 | byteBuffer.limit(curPosition); |
224 | try { | |
225 | 9 | byte first = b[0]; |
226 | 9 | int start = 0; |
227 | 9 | int end = curPosition; |
228 | ||
229 | // Look for first char | |
230 | 9 | int srcEnd = b.length; |
231 | ||
232 | 99 | for (int i = start; i <= (end - srcEnd); i++) { |
233 | 99 | if ((toLower[byteBuffer.get(i) & 0xff] & 0xff) != first) continue; |
234 | // found first char, now look for a match | |
235 | 27 | int myPos = i+1; |
236 | 27 | for (int srcPos = 1; srcPos < srcEnd; ) { |
237 | 108 | if ((toLower[byteBuffer.get(myPos++) & 0xff] & 0xff) != b[srcPos++]) |
238 | 18 | break; |
239 | 90 | if (srcPos == srcEnd) return i - start; // found it |
240 | } | |
241 | } | |
242 | 0 | return -1; |
243 | } finally { | |
244 | 9 | byteBuffer.limit(curLimit); |
245 | 9 | byteBuffer.position(curPosition); |
246 | } | |
247 | } | |
248 | } |