/*
* Copyright (C) 2006 http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
package org.chaidb.db.index;
import org.chaidb.db.api.Converter;
import org.chaidb.db.exception.EncodingException;
import org.chaidb.db.helper.ByteTool;
import java.util.AbstractList;
import java.util.ArrayList;
/**
* This is one of the stock converters. It converts a byte array containing
* concatenated ids to an array of byte arrays (an array of ids)
*
* @see org.chaidb.db.api.Converter
*/
public class IDConverter implements Converter {
/**
* encodes an array of byte arrays to a byte array which is a
* concatenation of all the byte arrays
*
* @param obj An array of ids
* @return The byte array containing the concatenation of all the arrays
*/
public byte[] encodeToByteArray(Object obj) throws EncodingException {
try {
byte[][] baa = (byte[][]) obj;
byte[] ret = new byte[baa.length * 8];
for (int i = 0; i < baa.length; i++)
System.arraycopy(baa[i], 0, ret, i * 8, 8);
return ret;
} catch (ClassCastException cce) {
throw new EncodingException("Invalid input type for converter");
}
}
/**
* decodes a byte array into an array of byte arrays
*
* @param key The key associated with this entry
* @param bytes A one dimensional byte array containing concatenated IDs
* @return A byte[][] which represents an array of ids
*/
public Object decodeFromByteArray(Key key, byte[] bytes) throws EncodingException {
if ((bytes.length % 8) != 0) throw new EncodingException("Trailing garbage in input");
byte[][] ret = new byte[bytes.length / 8][8];
for (int i = 0; i < ret.length; i++)
System.arraycopy(bytes, i * 8, ret[i], 0, 8);
return ret;
}
/**
* Adds a set of values to an existing set of values in the database. The
* new values are provided as a list of byte arrays.
*
* @param key The key for which the values are being updated
* @param existingValues The existing values in the database
* @param tbu The values to be updated as a list of byte arrays
* @return The new values after the existing values have been updated
* with the values in tbu.
* @throws EncodingException If a byte array representing a new
* value could not be decoded
*/
public Object addValues(Key key, Object existingValues, AbstractList tbu) throws EncodingException {
byte[][] current = null;
try {
current = (byte[][]) existingValues;
byte[][] newValues = null;
int i = 0;
if (current != null) {
newValues = new byte[current.length + tbu.size()][];
for (i = 0; i < current.length; i++)
newValues[i] = current[i];
} else {
newValues = new byte[tbu.size()][];
}
int numNewValues = tbu.size();
for (int j = 0; j < numNewValues; i++, j++)
newValues[i] = (byte[]) tbu.get(j);
return newValues;
} catch (ClassCastException cce) {
throw new EncodingException("Input values to this method were of incorrect type");
}
}
/*
* Deletes a set of values from an existing set of values in the database.
* The values to be deleted are provided as a list of byte arrays.
* @param key The key for which the values are being updated
* @param existingValues The existing values in the database
* @param tbu The values to be deleted as a list of byte arrays
* @exception EncodingException If a byte array representing a new
* value could not be decoded
* @return The new values after the existing values have been updated
* with the values in tbu.
*/
public Object deleteValues(Key key, Object existingValues, AbstractList tbu) throws EncodingException {
if (existingValues == null) return null;
byte[][] current = null;
ArrayList currentArray = null;
try {
current = (byte[][]) existingValues;
currentArray = new ArrayList(current.length);
// Insert all values into an array list
for (int i = 0; i < current.length; i++)
currentArray.add(current[i]);
// for each element of tbu, go through the array list, find the
// matching value and delete it. This is the stupid way, come
// up with a better algorithm later @@@@
int numTbu = tbu.size();
for (int i = 0; i < numTbu; i++) {
byte[] tbd = (byte[]) tbu.get(i);
int currentArraySize = currentArray.size();
for (int j = 0; j < currentArraySize; j++) {
byte[] currentBytes = (byte[]) currentArray.get(j);
if (ByteTool.compare(currentBytes, 0, tbd, 0, 8) == 0) {
currentArray.remove(j);
break;
}
}
// If the existing values have all been deleted, return null;
if (currentArray.size() == 0) return null;
}
// convert the arraylist into an array of byte arrays
int currentArraySize = currentArray.size();
byte[][] ret = new byte[currentArraySize][];
for (int i = 0; i < currentArraySize; i++)
ret[i] = (byte[]) currentArray.get(i);
return ret;
} catch (Exception e) {
throw new EncodingException(e.toString());
}
}
/**
* Initializes the converter. This is a no-op in this case. Just pass
* a null to this method.
*
* @param obj The initializer object
*/
public void initConverter(Object obj) {
}
}