/* * Copyright 2010 Bizosys Technologies Limited * * Licensed to the Bizosys Technologies Limited (Bizosys) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The Bizosys licenses this file * to you 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 com.bizosys.hsearch.filter; import java.io.UnsupportedEncodingException; /** * Forms a byte representation for a given java Data Type. */ public class Storable implements IStorable { /** * Unknown data type */ public static final byte BYTE_UNKNOWN = -1; /** * String data type constant */ public static final byte BYTE_STRING = 2; /** * Byte data type constant */ public static final byte BYTE_BYTE = 3; /** * Short data type constant */ public static final byte BYTE_SHORT = 4; /** * Integer data type constant */ public static final byte BYTE_INT = 5; /** * Long data type constant */ public static final byte BYTE_LONG = 6; /** * Boolean data type constant */ public static final byte BYTE_BOOLEAN = 7; /** * Character data type constant */ public static final byte BYTE_CHAR = 8; /** * Float data type constant */ public static final byte BYTE_FLOAT = 9; /** * Double data type constant */ public static final byte BYTE_DOUBLE = 10; /** * Date data type constant */ public static final byte BYTE_DATE = 11; /** * SQL data type constant */ public static final byte BYTE_SQLDATE = 12; /** * Storable data type constant */ public static final byte BYTE_STORABLE = 13; /** * As is object */ protected Object asIsObject = null; /** * The computed byte value */ protected byte[] byteValue = null; /** * The byte type defaulted to unknown */ public byte type = BYTE_UNKNOWN; /** * Constructor * @param origVal A byte data */ public Storable(byte origVal) { this.asIsObject = origVal; this.byteValue = new byte[] {origVal}; } /** * Constructor * @param origVal bytes data */ public Storable(byte[] origVal) { fromBytes(origVal, 0); } /** * Bytes with specified data type * @param inputBytes Value as bytes array * @param type Data Type */ public Storable(byte[] inputBytes, byte type) { if ( null != inputBytes) setValueWithParsing(inputBytes, type, 0, inputBytes.length); } /** * Bytes with specified data type * @param inputBytes Value as bytes array * @param type Data Type * @param startPos Starting position to read from bytes array */ public Storable(byte[] inputBytes, byte type, int startPos) { this(inputBytes,type,startPos,inputBytes.length); } /** /** * Bytes with specified data type * @param inputBytes Value as bytes array * @param type Data Type * @param startPos Starting position to read from bytes array * @param endPos End position of bytes array reading */ public Storable(byte[] inputBytes, byte type, int startPos, int endPos ) { if ( null != inputBytes) setValueWithParsing(inputBytes, type, startPos, endPos); } /** * Constructor * @param storable Bytes Serializable data types */ public Storable(IStorable storable) { this.asIsObject = storable; if ( null == storable) this.setValue(BYTE_STORABLE, null); else this.setValue(BYTE_STORABLE, storable.toBytes()); } /** * Constructor * @param origVal String data type */ public Storable(String origVal) { if ( null != origVal) { this.asIsObject = origVal; try { this.setValue(BYTE_STRING, origVal.getBytes("UTF-8")); } catch (Exception ex) { this.setValue(BYTE_STRING, origVal.getBytes()); } } } /** * Constructor * @param origVal Byte data type */ public Storable(Byte origVal) { this.asIsObject = origVal; this.setValue(BYTE_BYTE, new byte[]{origVal}); } /** * Constructor * @param origVal Short data type */ public Storable(Short origVal) { this.asIsObject = origVal; short temp = origVal.shortValue(); this.setValue(BYTE_SHORT, new byte[]{ (byte)(temp >> 8 & 0xff), (byte)(temp & 0xff) }); } /** * Constructor * @param origVal Integer data type */ public Storable(Integer origVal) { this.asIsObject = origVal; this.setValue(BYTE_INT, putInt(origVal) ) ; } /** * Constructor * @param origVal Long data type */ public Storable(Long origVal) { this.asIsObject = origVal; this.setValue(BYTE_LONG, putLong(origVal) ) ; } /** * Constructor * @param origVal Float data type */ public Storable(Float origVal) { this.asIsObject = origVal; this.setValue(BYTE_FLOAT, putInt(Float.floatToRawIntBits (origVal)) ) ; } /** * Constructor * @param origVal Double data type */ public Storable(Double origVal) { this.asIsObject = origVal; if ( null != origVal ) this.setValue(BYTE_DOUBLE, putLong(Double.doubleToRawLongBits(origVal)) ) ; } /** * Constructor * @param bolVal Boolean data type */ public Storable(Boolean bolVal) { this.asIsObject = bolVal; if ( true == bolVal) this.setValue(BYTE_BOOLEAN, new byte[]{1}); else this.setValue(BYTE_BOOLEAN, new byte[]{0}); } /** * Constructor * @param charVal Character data type */ public Storable(Character charVal) { this.asIsObject = charVal; char temp = charVal.charValue(); this.setValue(BYTE_CHAR, new byte[]{ (byte)(temp >> 8 & 0xff), (byte)(temp & 0xff) }); } /** * Constructor * @param date Date data type */ public Storable(java.util.Date date) { this.asIsObject = date; if ( null != date ) this.setValue(BYTE_DATE, putLong(date.getTime()) ) ; } /** * Constructor * @param date Date data type */ public Storable(java.sql.Date date) { this.asIsObject = date; this.setValue(BYTE_SQLDATE, putLong(date.getTime()) ) ; } /** * Set the bytes data value with type information * @param type * @param byteA */ public void setValue(byte type, byte[] byteA) { if ( null == byteA) return; this.type = type; this.byteValue = byteA; } /** * Set the value after parsing the bytes data * @param inputBytes Data as bytes array * @param type Data type * @param startPos bytes-array read From position * @param endPos bytes-array read To position */ protected void setValueWithParsing(byte[] inputBytes, byte type, int startPos, int endPos) { this.byteValue = inputBytes; this.type = type; switch (type) { case BYTE_CHAR: this.asIsObject = (char) ( (inputBytes[startPos] << 8 ) + ( inputBytes[++startPos] & 0xff ) ); break; case BYTE_STORABLE: int destBytesT = endPos - startPos; byte[] bytes = new byte[destBytesT]; System.arraycopy(inputBytes, startPos, bytes, 0, destBytesT); this.asIsObject = bytes; break; case BYTE_STRING: int dBytesT = endPos - startPos; byte[] value = new byte[dBytesT]; System.arraycopy(inputBytes, startPos, value, 0, dBytesT); try { this.asIsObject = new String( value , "UTF-8"); } catch (UnsupportedEncodingException ex) { this.asIsObject = new String(value); } break; case BYTE_SHORT: this.asIsObject = getShort(startPos, inputBytes); break; case BYTE_INT: this.asIsObject = getInt(startPos, inputBytes); break; case BYTE_LONG: this.asIsObject = getLong(startPos,inputBytes); break; case BYTE_FLOAT: int fVal = getInt(startPos,inputBytes); this.asIsObject = Float.intBitsToFloat (fVal); break; case BYTE_DOUBLE: long dVal = getLong(startPos,inputBytes); this.asIsObject = Double.longBitsToDouble(dVal); break; case BYTE_DATE: long utilDate = getLong(startPos, inputBytes); this.asIsObject = new java.util.Date(utilDate); break; case BYTE_SQLDATE: long sqldate = getLong(startPos, inputBytes); this.asIsObject = new java.sql.Date(sqldate); break; default: break; } } /** * Get the As Is object data * @return Data object */ public Object getValue() { return this.asIsObject; } /** * Serialize set data to bytes */ public byte[] toBytes() { return this.byteValue; } public int fromBytes(byte[] data, int pos) { this.asIsObject = data; this.byteValue = data; if ( null != data ) return data.length; return pos; } /** * Compare byte values * @param offset Starting position of compare with Byte Array * @param inputBytes Compare with Bytes * @param compareBytes Compare to Bytes * @return True if matches */ public static boolean compareBytes(int offset, byte[] inputBytes, byte[] compareBytes) { int inputBytesT = inputBytes.length; int compareBytesT = compareBytes.length; if ( compareBytesT != inputBytesT - offset) return false; if ( compareBytes[0] != inputBytes[offset]) return false; if ( compareBytes[compareBytesT - 1] != inputBytes[compareBytesT + offset - 1] ) return false; switch (compareBytesT) { case 3: return compareBytes[1] == inputBytes[1 + offset]; case 4: return compareBytes[1] == inputBytes[1 + offset] && compareBytes[2] == inputBytes[2 + offset]; case 5: return compareBytes[1] == inputBytes[1+ offset] && compareBytes[2] == inputBytes[2+ offset] && compareBytes[3] == inputBytes[3+ offset]; case 6: return compareBytes[1] == inputBytes[1+ offset] && compareBytes[3] == inputBytes[3+ offset] && compareBytes[2] == inputBytes[2+ offset] && compareBytes[4] == inputBytes[4+ offset]; case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: for ( int i=offset; i< compareBytesT - 1; i++) { if ( compareBytes[i] != inputBytes[offset + i]) return false; } break; case 31: for ( int a = 1; a <= 6; a++) { if ( ! (compareBytes[a] == inputBytes[a+offset] && compareBytes[a+6] == inputBytes[a+6+offset] && compareBytes[a+12] == inputBytes[a+12+offset] && compareBytes[a+18] == inputBytes[a+18+offset] && compareBytes[a+24] == inputBytes[a+24+offset]) ) return false; } break; default: for ( int i=offset; i< compareBytesT - 1; i++) { if ( compareBytes[i] != inputBytes[offset + i]) return false; } } return true; } /** * Compare two bytes * @param inputBytes Compare with Bytes * @param compareBytes Compare to Bytes * @return True if matches */ public static boolean compareBytes(byte[] inputBytes, byte[] compareBytes) { return compareBytes(0,inputBytes,compareBytes); } /** * Compare two characters * @param inputBytes Compare with character array * @param compareBytes Compare to character array * @return True if matches */ public static boolean compareBytes(char[] inputBytes, char[] compareBytes) { int inputBytesT = inputBytes.length; int compareBytesT = compareBytes.length; if ( compareBytesT != inputBytesT) return false; if ( compareBytes[0] != inputBytes[0]) return false; if ( compareBytes[compareBytesT - 1] != inputBytes[compareBytesT - 1] ) return false; switch (compareBytesT) { case 3: return compareBytes[1] == inputBytes[1]; case 4: return compareBytes[1] == inputBytes[1] && compareBytes[2] == inputBytes[2]; case 5: return compareBytes[1] == inputBytes[1] && compareBytes[2] == inputBytes[2] && compareBytes[3] == inputBytes[3]; case 6: return compareBytes[1] == inputBytes[1] && compareBytes[3] == inputBytes[3] && compareBytes[2] == inputBytes[2] && compareBytes[4] == inputBytes[4]; default: compareBytesT--; for ( int i=0; i< compareBytesT; i++) { if ( compareBytes[i] != inputBytes[i]) return false; } } return true; } /** * Form a short value reading 2 bytes * @param startPos Bytes read start position * @param inputBytes Input Bytes * @return Short representation */ public static short getShort(int startPos, byte[] inputBytes) { return (short) ( (inputBytes[startPos] << 8 ) + ( inputBytes[++startPos] & 0xff ) ); } /** * Forms a byte array from a Short data * @param value Short data * @return 2 bytes */ public static byte[] putShort( short value ) { return new byte[] { (byte)(value >> 8 & 0xff), (byte)(value & 0xff) }; } /** * Form a integer value reading 4 bytes * @param index Bytes read start position * @param inputBytes Input Bytes * @return Integer representation */ public static int getInt(int index, byte[] inputBytes) { int intVal = (inputBytes[index] << 24 ) + ( (inputBytes[++index] & 0xff ) << 16 ) + ( ( inputBytes[++index] & 0xff ) << 8 ) + ( inputBytes[++index] & 0xff ); return intVal; } /** * Forms a byte array from a Integer data * @param value Integer data * @return 4 bytes */ public static byte[] putInt( int value ) { return new byte[] { (byte)(value >> 24), (byte)(value >> 16 ), (byte)(value >> 8 ), (byte)(value) }; } /** * Form a Long value reading 8 bytes * @param index Bytes read start position * @param inputBytes Input Bytes * @return Long representation */ public static long getLong(int index, final byte[] inputBytes) { if ( 0 == inputBytes.length) return 0; long longVal = ( ( (long) (inputBytes[index]) ) << 56 ) + ( (inputBytes[++index] & 0xffL ) << 48 ) + ( (inputBytes[++index] & 0xffL ) << 40 ) + ( (inputBytes[++index] & 0xffL ) << 32 ) + ( (inputBytes[++index] & 0xffL ) << 24 ) + ( (inputBytes[++index] & 0xff ) << 16 ) + ( (inputBytes[++index] & 0xff ) << 8 ) + ( inputBytes[++index] & 0xff ); return longVal; } /** * Forms a byte array from a long data * @param value Long data * @return 8 bytes */ public static byte[] putLong(long value) { return new byte[]{ (byte)(value >> 56), (byte)(value >> 48 ), (byte)(value >> 40 ), (byte)(value >> 32 ), (byte)(value >> 24 ), (byte)(value >> 16 ), (byte)(value >> 8 ), (byte)(value ) }; } /** * Form a String value format UTF-8 * @param inputObj Input String * @return bytes representation */ public static byte[] putString( String inputObj) { try { return inputObj.getBytes("UTF-8"); } catch (UnsupportedEncodingException ex) { return inputObj.getBytes(); } } /** * Parse a byte array to form a UTF-8 String * @param inputBytes Input bytes array * @return A UTF-8 String */ public static String getString(byte[] inputBytes) { try { return new String( inputBytes , "UTF-8"); } catch (UnsupportedEncodingException ex) { return new String(inputBytes); } } /** * Get the size for a given data type * @param type Data type * @return The bytes-array size */ public static int getSize(byte type) { int size = -1; switch(type) { case BYTE_SHORT: size = Short.SIZE; break; case BYTE_INT: size = Integer.SIZE; break; case BYTE_LONG: size = Long.SIZE; break; case BYTE_BOOLEAN: size = 1; break; case BYTE_CHAR: size = Character.SIZE; break; case BYTE_FLOAT: size = Float.SIZE; break; case BYTE_DOUBLE: size = Double.SIZE; break; case BYTE_DATE: size = Long.SIZE; break; case BYTE_SQLDATE: size = Long.SIZE; break; default: size = -1; } return size; } /** * Convert a byte to a 8 bits * @param b A byte * @return 8 bits */ public static final boolean[] byteToBits(byte b) { boolean[] bits = new boolean[8]; for (int i = 0; i < bits.length; i++) { bits[i] = ((b & (1 << i)) != 0); } return bits; } /** * Convert 8 bits to a Byte * @param bits Bits array. Reading happens from position 0 * @return 1 Byte */ public static byte bitsToByte(boolean[] bits) { return bitsToByte(bits, 0); } /** * Converting 8 Bits to a Byte * @param bits array of bits * @param offset Read starting position * @return 1 Byte */ public static byte bitsToByte(boolean[] bits, int offset) { int value = 0; for (int i = 0; i < 8; i++) { if(bits[i] == true) { value = value | (1 << i); } } return (byte)value; } @Override public String toString() { if ( null != this.asIsObject) return this.asIsObject.toString(); else return ""; } }