package com.dbxml.xml.dtsm;
/*
* dbXML - Native XML Database
* Copyright (c) 1999-2006 The dbXML Group, L.L.C.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* $Id: TableBuilder.java,v 1.4 2006/02/02 19:04:46 bradford Exp $
*/
import com.dbxml.db.core.data.Value;
import com.dbxml.xml.QName;
import com.dbxml.xml.SymbolTable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* TableBuilder
*/
public final class TableBuilder {
private BuiltDocumentTable table = new BuiltDocumentTable();
private SymbolTable symbols;
private List entries = new ArrayList();
private List values = new ArrayList();
private Map map = new HashMap();
private int nextValID;
private int dataSize;
public TableBuilder() {
}
public TableBuilder(SymbolTable symbols) {
this.symbols = symbols;
}
/**
* getSymbolTable returns the SymbolTable that is associated
* with this TableBuilder.
*
* @return the SymbolTable
*/
public SymbolTable getSymbolTable() {
return symbols;
}
/**
* setSymbolTable sets the SymbolTable that will be associated
* with this TableBuilder.
*
* @param symbols the SymbolTable
*/
public void setSymbolTable(SymbolTable symbols) {
this.symbols = symbols;
}
/**
* addEntry adds an entry to the table with no associated
* Symbol ID or Value ID.
*
* @see com.dbxml.xml.dtsm.Constants
*
* @param typeID The Type ID
*/
public void addEntry(byte typeID) {
entries.add(new DocumentTableEntry(typeID, Constants.NO_SYMBOL_ID));
}
/**
* addEntry adds an entry to the DocumentTable and returns
* the Symbol ID that the qname maps to. The Symbol ID
* can be used to generate end entries more rapidly.
*
* @see com.dbxml.xml.dtsm.Constants
*
* @param typeID The Type ID
* @param qname The QName
* @return The Symbol ID
*/
public int addEntry(byte typeID, QName qname) {
int id = symbols.getSymbol(qname, true);
entries.add(new DocumentTableEntry(typeID, id));
return id;
}
/**
* addEntry adds an entry to the DocumentTable.
*
* @see com.dbxml.xml.dtsm.Constants
*
* @param typeID The Type ID
* @return symbolID The Symbol ID
*/
public void addEntry(byte typeID, int symbolID) {
entries.add(new DocumentTableEntry(typeID, symbolID));
}
/**
* addEntry adds an entry to the DocumentTable and
* return the Value ID that the data produces.
*
* @see com.dbxml.xml.dtsm.Constants
*
* @param typeID The Type ID
* @param data The data to store
*/
public void addEntry(byte typeID, byte[] data) {
ValueWrapper w = new ValueWrapper(data);
ValueWrapper c = (ValueWrapper)map.get(w);
if ( c == null ) {
c = w;
c.valID = nextValID++;
map.put(c, c);
Value v = new Value(c.data);
ValueTableEntry e = new ValueTableEntry(dataSize, c.data.length);
values.add(new ValueInfo(v, e));
dataSize += c.data.length;
}
entries.add(new DocumentTableEntry(typeID, c.valID));
}
/**
* getDataSize returns the total number of bytes that are being
* stored as unique Values.
*
* @return the total data size
*/
public int getDataSize() {
return dataSize;
}
/**
* buildDocumentTable instructs the TableBuilder to take all of
* the information it has accumulated, and to produce a
* DocumentTable.
*
* @return the DocumentTable
*/
public DocumentTable buildDocumentTable() {
return table;
}
/**
* BuiltDocumentTable
*/
private class BuiltDocumentTable implements DocumentTable {
public SymbolTable getSymbolTable() {
return symbols;
}
public int getEntryCount() {
return entries.size();
}
public DocumentTableEntry getEntry(int idx) {
return (DocumentTableEntry)entries.get(idx);
}
public int getValueCount() {
return values.size();
}
public ValueTableEntry getValueEntry(int idx) {
return ((ValueInfo)values.get(idx)).entry;
}
public Value getValue(int idx) {
return ((ValueInfo)values.get(idx)).value;
}
}
/**
* ValueWrapper
*/
private class ValueWrapper {
public byte[] data;
public int valID;
public int hash;
public ValueWrapper(byte[] data) {
this.data = data;
calculateHash();
}
public ValueWrapper(byte[] data, int valID) {
this.data = data;
this.valID = valID;
calculateHash();
}
private void calculateHash() {
hash = 0;
for ( int i = 0; i < data.length; i++ ) {
hash = (hash << 5) ^ data[i];
hash = hash % 1234567891;
}
hash = Math.abs(hash);
}
public int hashCode() {
return hash;
}
public boolean equals(Object o) {
ValueWrapper w = (ValueWrapper)o;
if ( hash != w.hash || data.length != w.data.length )
return false;
for ( int i = 0; i < data.length; i++ )
if ( data[i] != w.data[i] )
return false;
return true;
}
}
/**
* ValueInfo
*/
private class ValueInfo {
public Value value;
public ValueTableEntry entry;
public ValueInfo(Value value, ValueTableEntry entry) {
this.value = value;
this.entry = entry;
}
}
}