package org.yamcs.yarch; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.yamcs.yarch.PartitioningSpec._type; import org.yamcs.yarch.TableDefinition.PartitionStorage; import org.yamcs.yarch.streamsql.StreamSqlException; import org.yaml.snakeyaml.constructor.AbstractConstruct; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.nodes.MappingNode; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.ScalarNode; import org.yaml.snakeyaml.nodes.SequenceNode; import org.yaml.snakeyaml.nodes.Tag; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import static org.yamcs.yarch.TableDefinitionRepresenter.*; /** * Constructs {@link org.yamcs.yarch.TableDefinition} from .def yaml files. * * */ public class TableDefinitionConstructor extends Constructor { public TableDefinitionConstructor() { this.yamlConstructors.put(new Tag("TableDefinition"), new ConstructTableDefinition()); this.yamlConstructors.put(new Tag("TupleDefinition"), new ConstructTupleDefinition()); this.yamlConstructors.put(new Tag("PartitioningSpec"), new ConstructPartitioningSpec()); this.yamlConstructors.put(new Tag("PartitionStorage"), new ConstructPartitionStorage()); } private class ConstructTableDefinition extends AbstractConstruct { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Object construct(Node node) { Map<String, Object> m = (Map) constructMapping((MappingNode)node); TupleDefinition keyDef=(TupleDefinition) m.get(K_KEY_DEF); TupleDefinition valueDef=(TupleDefinition) m.get(K_VALUE_DEF); Map<String, BiMap<String,Short>> enumValues=new HashMap<>(); if(m.containsKey(K_ENUM_VALUE)) { Map<String, Map<String, Integer>> t=(Map)m.get(K_ENUM_VALUE); for(Entry<String, Map<String, Integer>> e:t.entrySet()) { BiMap<String, Short> b=HashBiMap.create(); for(Entry<String,Integer> e1:e.getValue().entrySet()) { b.put(e1.getKey(), (short)(int)e1.getValue()); } enumValues.put(e.getKey(), b); } } TableDefinition tdef=new TableDefinition(keyDef, valueDef, enumValues); if(m.containsKey(K_HISTOGRAM)) { List<String> h=(List<String>)m.get(K_HISTOGRAM); try { tdef.setHistogramColumns(h); } catch (StreamSqlException e) { throw new IllegalArgumentException(e); } } if(m.containsKey(K_DATA_DIR)) { tdef.setCustomDataDir(true); tdef.setDataDir((String)m.get(K_DATA_DIR)); } try { if(m.containsKey(K_PARTITIONING_SPEC)) { tdef.setPartitioningSpec((PartitioningSpec)m.get(K_PARTITIONING_SPEC)); } else { PartitioningSpec ps = PartitioningSpec.noneSpec(); tdef.setPartitioningSpec(ps); } } catch (StreamSqlException e) { throw new IllegalArgumentException(e); } if(m.containsKey(K_COMPRESSED)) { tdef.setCompressed((Boolean)m.get(K_COMPRESSED)); } if(m.containsKey(K_FORMAT_VERSION)) { tdef.setFormatVersion((Integer)m.get(K_FORMAT_VERSION)); } else { tdef.setFormatVersion(0); } if(m.containsKey(K_STORAGE_ENGINE)) { tdef.setStorageEngineName((String)m.get(K_STORAGE_ENGINE)); } else {//before the storageEngine has been invented, we only had TokyoCabinet, so assume that if it's not set then TokyoCabine is used tdef.setStorageEngineName("TokyoCabinet"); } if(m.containsKey(K_PARTITION_STORAGE)) { tdef.setPartitionStorage((PartitionStorage)m.get(K_PARTITION_STORAGE)); } else {//before the partitionStorage has been invented, we only had column_family tdef.setPartitionStorage(PartitionStorage.COLUMN_FAMILY); } return tdef; } } private class ConstructTupleDefinition extends AbstractConstruct { @SuppressWarnings({"unchecked","rawtypes"}) @Override public Object construct(Node node) { List<Object> l = (List) constructSequence((SequenceNode)node); ArrayList<ColumnDefinition> cols=new ArrayList<ColumnDefinition>(); for(Object o:l) { Map<String, Object> m=(Map)o; Object o1=m.get("idx"); if((o1==null) || !(o1 instanceof Integer)){ throw new IllegalArgumentException("idx not specified or not integer"); } int idx=(Integer)o1; if(idx>TupleDefinition.MAX_COLS){ throw new IllegalArgumentException("got idx="+idx+" but max_cols="+TupleDefinition.MAX_COLS); } String name=(String)m.get("name"); if(name==null) { throw new IllegalArgumentException("name not specifie for column with index idx="+idx); } DataType type = DataType.byName((String)m.get("type")); ColumnDefinition cd = new ColumnDefinition(name, type); for(int i=cols.size();i<idx+1;i++) { cols.add(null); } cols.set(idx, cd); } TupleDefinition td=new TupleDefinition(); for(int i=0;i<cols.size();i++) { ColumnDefinition cd=cols.get(i); if(cd==null) { throw new IllegalArgumentException("Column with idx "+i+" not specified"); } td.addColumn(cd); } return td; } } private class ConstructPartitioningSpec extends AbstractConstruct { @SuppressWarnings({"unchecked","rawtypes"}) @Override public Object construct(Node node) { Map<String, Object> m = (Map) constructMapping((MappingNode)node); if(!m.containsKey("type")){ throw new IllegalArgumentException("partitioning spec type not specified"); } PartitioningSpec pspec; PartitioningSpec._type type = PartitioningSpec._type.valueOf((String)m.get("type")); if(type==_type.NONE) { pspec = PartitioningSpec.noneSpec(); } else if(type==_type.TIME) { String timeColumn = (String)m.get(K_TIME_COLUMN); pspec = PartitioningSpec.timeSpec(timeColumn); } else if((type==_type.VALUE)) { String valueColumn = (String)m.get(K_VALUE_COLUMN); pspec = PartitioningSpec.valueSpec(valueColumn); } else if(type==_type.TIME_AND_VALUE) { String timeColumn = (String)m.get(K_TIME_COLUMN); String valueColumn = (String)m.get(K_VALUE_COLUMN); pspec = PartitioningSpec.timeAndValueSpec(timeColumn, valueColumn); } else { throw new IllegalArgumentException("Unkwnon partitioning type "+type); } if(m.containsKey(K_TIME_PARTITIONING_SCHEMA)) { pspec.setTimePartitioningSchema((String)m.get(K_TIME_PARTITIONING_SCHEMA)); } else { pspec.setTimePartitioningSchema("YYYY/DOY"); } return pspec; } } private class ConstructPartitionStorage extends AbstractConstruct { @Override public Object construct(Node node) { String ps = (String) constructScalar((ScalarNode)node); return PartitionStorage.valueOf(ps.toUpperCase()); } } }