| 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 | 971 | int count = 1; |
| 92 | 971 | int byteRead = 0; |
| 93 | 971 | int preReadInputBBPos = byteBuffer.position(); |
| 94 | 971 | Selector readSelector = null; |
| 95 | 971 | SelectionKey tmpKey = null; |
| 96 | ||
| 97 | try { | |
| 98 | 971 | ReadableByteChannel readableChannel = (ReadableByteChannel) channel; |
| 99 | 2208 | while (count > 0){ |
| 100 | 1238 | count = readableChannel.read(byteBuffer); |
| 101 | 1237 | if ( count > -1 ) |
| 102 | 1236 | byteRead += count; |
| 103 | else | |
| 104 | 1 | byteRead = count; |
| 105 | } | |
| 106 | ||
| 107 | 970 | if (byteRead == 0 && byteBuffer.position() == preReadInputBBPos) { |
| 108 | 704 | readSelector = SelectorFactory.getSelector(); |
| 109 | ||
| 110 | 704 | if ( readSelector == null ){ |
| 111 | 0 | return 0; |
| 112 | } | |
| 113 | 704 | count = 1; |
| 114 | ||
| 115 | 704 | tmpKey = channel.register(readSelector, SelectionKey.OP_READ); |
| 116 | 704 | tmpKey.interestOps(tmpKey.interestOps() | SelectionKey.OP_READ); |
| 117 | 704 | int code = readSelector.select(readTimeout); |
| 118 | 704 | tmpKey.interestOps( |
| 119 | tmpKey.interestOps() & (~SelectionKey.OP_READ)); | |
| 120 | ||
| 121 | 704 | if ( code == 0 ){ |
| 122 | 0 | return 0; // Return on the main Selector and try again. |
| 123 | } | |
| 124 | ||
| 125 | 2147 | while (count > 0){ |
| 126 | 1443 | count = readableChannel.read(byteBuffer); |
| 127 | 1443 | if ( count > -1 ) |
| 128 | 1442 | byteRead += count; |
| 129 | else | |
| 130 | 1 | byteRead = count; |
| 131 | } | |
| 132 | 704 | } else if (byteRead == 0 && byteBuffer.position() != preReadInputBBPos) { |
| 133 | 0 | byteRead += (byteBuffer.position() - preReadInputBBPos); |
| 134 | } | |
| 135 | } finally { | |
| 136 | 971 | if (tmpKey != null) |
| 137 | 704 | tmpKey.cancel(); |
| 138 | ||
| 139 | 971 | if ( readSelector != null) { |
| 140 | // Bug 6403933 | |
| 141 | 704 | SelectorFactory.selectNowAndReturnSelector(readSelector); |
| 142 | } | |
| 143 | } | |
| 144 | ||
| 145 | 970 | 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 | } |