/* * Copyright 2011 Paula Gearon. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mulgara.util.io; import java.io.BufferedReader; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import org.apache.log4j.Logger; /** * Static utility methods for common actions on IO. */ public class IOUtil { /** The logger. */ private static final Logger logger = Logger.getLogger(IOUtil.class); /** The system property for the byte order. */ public static final String BYTE_ORDER_PROPERTY = "mulgara.xa.useByteOrder"; /** The property for the block type. May be "direct" or "javaHeap" */ public static final String MEM_TYPE_PROP = "mulgara.xa.memoryType"; /** Native ordering of the bytes */ public static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder(); /** The endianness of this computer. */ private static final ByteOrder byteOrder; /** Enumeration of the different memory types for blocks */ public enum BlockMemoryType { DIRECT, HEAP }; /** The default value to use for the block memory type. Used when nothing is configured. */ private static final BlockMemoryType DEFAULT = BlockMemoryType.DIRECT; /** The configured type of block type to use. */ private static final BlockMemoryType BLOCK_TYPE; static { // Determine the byte order of this machine, and select an ordering to use. * String useByteOrderProp = System.getProperty(BYTE_ORDER_PROPERTY, "native"); ByteOrder bo = ByteOrder.nativeOrder(); if (useByteOrderProp != null) { if (useByteOrderProp.equalsIgnoreCase("native")) { bo = ByteOrder.nativeOrder(); } else if (useByteOrderProp.equalsIgnoreCase("big_endian")) { bo = ByteOrder.BIG_ENDIAN; } else if (useByteOrderProp.equalsIgnoreCase("little_endian")) { bo = ByteOrder.LITTLE_ENDIAN; } else { logger.warn("Invalid value for property mulgara.xa.useByteOrder: " + useByteOrderProp); } } byteOrder = bo; // initialize the type of memory block to be used: heap or direct // configured with mulgara.xa.memoryType String defBlockType = System.getProperty(MEM_TYPE_PROP, DEFAULT.name()); if (defBlockType.equalsIgnoreCase(BlockMemoryType.DIRECT.name())) { BLOCK_TYPE = BlockMemoryType.DIRECT; } else if (defBlockType.equalsIgnoreCase(BlockMemoryType.HEAP.name())) { BLOCK_TYPE = BlockMemoryType.HEAP; } else { logger.warn("Invalid value for property " + MEM_TYPE_PROP + ": " + defBlockType); BLOCK_TYPE = DEFAULT; } } /** * Retrieves the configured byte ordering to use. Uses the default if nothing is set. * @return The configured byte order. */ public static final ByteOrder getByteOrder() { return byteOrder; } /** * Reads the next non-empty line of text from a buffered reader, up to a given * number of characters. * * @param br The BufferedReader to get a line from. * @param maxlen The maximum length of string to read from the line. * @return A line of text, not including any line-termination characters, * or null if the end of stream has been reached. An empty string will * indicate that the maxlen number of characters was reached before any * text could be read. */ public static final String readLine(BufferedReader br, int maxlen) throws IOException { StringBuilder s = new StringBuilder(); for (int i = 0; i < maxlen; i++) { int c = br.read(); if (c == -1) { if (s.length() == 0) return null; break; } if (c == '\n' || c == '\r') { if (s.length() == 0) continue; break; } s.appendCodePoint(c); } return s.toString(); } /** * Allocates data according to the system configured memory model. * @param size The number of bytes in the allocated buffer. * @return the allocated buffer. */ public static final ByteBuffer allocate(int size) { return allocate(size, byteOrder); } /** * Allocates data according to the system configured memory model. * @param size The number of bytes in the allocated buffer. * @param order The byteorder to use in the buffer. * @return the allocated buffer. */ public static final ByteBuffer allocate(int size, ByteOrder order) { return BLOCK_TYPE == BlockMemoryType.DIRECT ? (order == NATIVE_ORDER ? ByteBuffer.allocateDirect(size) : ByteBuffer.allocateDirect(size).order(order)) : (order == NATIVE_ORDER ? ByteBuffer.allocate(size) : ByteBuffer.allocate(size).order(order)); } /** * Mix an int into a long in a reasonably cheap way. * @param The int to mix. * @return A long value with the integer mixed into it. Positive numbers only. */ public static final long longHash(int h) { long v = (long)h; v ^= v << 5; v ^= (v << 11) ^ 1049; v ^= ((v >> 32) | (v << 32)); v ^= (v << 17) ^ 131041; v ^= ((v >> 56) | (v << 56)); v ^= (v << 23) ^ 8313581; v ^= (((v >> 8) & 0xFF000000L) | ((v << 8) & 0xFF00000000L)); v ^= (v << 37) ^ 2147483659L; v ^= ((v >> 32) | (v << 32)); return v & 0x7FFFFFFFFFFFFFFFL; } /** * Convert an int into a long hash in a cheap way. * @param The int to hash. * @return A long value as an integer hash. */ public static final long hashCode(int h) { return ((long)h | (long)h << 32); } public static final long hashCode(long h) { return h; } /** * Determines the hashCode of a string, stretched out to a long, instead of just an int. * @param s The string to determine the hashCode for. * @return The hashcode. */ public static final long hashCode(String s) { long h = 0; char val[] = s.toCharArray(); for (int i = 0; i < val.length; i++) h = 31 * h + val[i]; return h; } public static final long hashCode(ByteBuffer bb) { long h = 1; int p = bb.position(); for (int i = bb.limit() - 1; i >= p; i--) h = 31 * h + (long)bb.get(i); return h; } }