package com.github.lindenb.jvarkit.util.vcf.bdb; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.sleepycat.bind.tuple.BigDecimalBinding; import com.sleepycat.bind.tuple.BigIntegerBinding; import com.sleepycat.bind.tuple.BooleanBinding; import com.sleepycat.bind.tuple.ByteBinding; import com.sleepycat.bind.tuple.CharacterBinding; import com.sleepycat.bind.tuple.DoubleBinding; import com.sleepycat.bind.tuple.FloatBinding; import com.sleepycat.bind.tuple.IntegerBinding; import com.sleepycat.bind.tuple.LongBinding; import com.sleepycat.bind.tuple.ShortBinding; import com.sleepycat.bind.tuple.StringBinding; import com.sleepycat.bind.tuple.TupleBinding; import com.sleepycat.bind.tuple.TupleInput; import com.sleepycat.bind.tuple.TupleOutput; /** * Base class for serializing some java.lang.Object in a VCF (in INFO and Genotype) * @author lindenb * * @param <T> */ @SuppressWarnings({"rawtypes","unchecked"}) public abstract class AbstractVCFBinding<T> extends TupleBinding<T> { /** array of tuple com.sleepycat.bind.tuple.*Binding to serialize some simple objects */ private static final List<TupleBinding> INDEX_TO_BINDING=new ArrayList<TupleBinding>(); /** map java.langClass to an index in INDEX_TO_BINDING */ private static final Map<Class,Integer> CLASS_TO_BINDING_INDEX=new HashMap<Class, Integer>(); static { addClassBinding(Byte.class,Byte.TYPE,new ByteBinding()); addClassBinding(Short.class,Short.TYPE,new ShortBinding()); addClassBinding(Integer.class,Integer.TYPE,new IntegerBinding()); addClassBinding(Long.class,Long.TYPE,new LongBinding()); addClassBinding(Float.class,Float.TYPE,new FloatBinding()); addClassBinding(Double.class,Double.TYPE,new DoubleBinding()); addClassBinding(Character.class,Character.TYPE,new CharacterBinding()); addClassBinding(Boolean.class,Boolean.TYPE,new BooleanBinding()); addClassBinding(String.class,null,new StringBinding()); addClassBinding(BigDecimal.class,null,new BigDecimalBinding()); addClassBinding(BigInteger.class,null,new BigIntegerBinding()); } /** add this opcode to tell that and object is an 'array-of' */ private static final byte OP_ARRAY=(byte)100; /**put binding for this primitive */ private static <T> void addClassBinding(Class<T> c1,Class<T> c2,TupleBinding<T> bind) { CLASS_TO_BINDING_INDEX.put(c1, INDEX_TO_BINDING.size()); INDEX_TO_BINDING.add(bind); if(c2!=null) addClassBinding(c2,null,bind); } protected AbstractVCFBinding() { } /** unserialize any object using opcodes */ protected Object readAttribute(TupleInput in) { byte opcode=in.readByte(); /* this is an array */ if(opcode>=OP_ARRAY) { int n_items=in.readInt(); TupleBinding bind=INDEX_TO_BINDING.get(opcode-OP_ARRAY); List array=new ArrayList(n_items); for(int i=0;i< n_items;++i) { array.add(bind.entryToObject(in)); } return array; } /* this is a simple type */ TupleBinding bind=INDEX_TO_BINDING.get(opcode); return bind.entryToObject(in); } /** serialize any object using opcodes */ protected void writeAttribute(TupleOutput out,Object o) { /* this is an array */ if(o.getClass().isArray()) { Class clazz=o.getClass().getComponentType(); int idx=CLASS_TO_BINDING_INDEX.get(clazz); TupleBinding bind=INDEX_TO_BINDING.get(idx); out.writeByte((byte)(idx+OP_ARRAY));/* add opcode for array */ Object array[]=(Object[])o; out.writeInt(array.length); for(int i=0;i< array.length;++i) { bind.objectToEntry(array[i], out); } } /* this is a list */ else if(o instanceof List) { List array=(List)o; Class clazz=array.isEmpty()?Byte.class:array.get(0).getClass(); int idx=CLASS_TO_BINDING_INDEX.get(clazz); TupleBinding bind=INDEX_TO_BINDING.get(idx); out.writeByte((byte)(idx+OP_ARRAY));/* add opcode for array */ out.writeInt(array.size()); for(int i=0;i< array.size();++i) { bind.objectToEntry(array.get(i), out); } } /* this is a simple object */ else { int idx= CLASS_TO_BINDING_INDEX.get(o.getClass()); TupleBinding bind=INDEX_TO_BINDING.get(idx); out.writeByte((byte)idx); bind.objectToEntry(o, out); } } }