/*
* Copyright © 2014 Cask Data, Inc.
*
* Licensed 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 co.cask.cdap.explore.service.datasets;
import co.cask.cdap.api.common.Bytes;
import co.cask.cdap.api.data.batch.RecordScannable;
import co.cask.cdap.api.data.batch.RecordScanner;
import co.cask.cdap.api.data.batch.Scannables;
import co.cask.cdap.api.data.batch.Split;
import co.cask.cdap.api.dataset.DatasetAdmin;
import co.cask.cdap.api.dataset.DatasetContext;
import co.cask.cdap.api.dataset.DatasetDefinition;
import co.cask.cdap.api.dataset.DatasetProperties;
import co.cask.cdap.api.dataset.DatasetSpecification;
import co.cask.cdap.api.dataset.lib.AbstractDataset;
import co.cask.cdap.api.dataset.lib.AbstractDatasetDefinition;
import co.cask.cdap.api.dataset.module.DatasetDefinitionRegistry;
import co.cask.cdap.api.dataset.module.DatasetModule;
import co.cask.cdap.api.dataset.table.Row;
import co.cask.cdap.api.dataset.table.Table;
import com.google.gson.Gson;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* Dataset definition with a record scannable table, containing an extensive schema. Used for testing.
*/
public class ExtensiveSchemaTableDefinition
extends AbstractDatasetDefinition<ExtensiveSchemaTableDefinition.ExtensiveSchemaTable, DatasetAdmin> {
private static final Gson GSON = new Gson();
private final DatasetDefinition<? extends Table, ?> tableDef;
public ExtensiveSchemaTableDefinition(String name, DatasetDefinition<? extends Table, ?> orderedTableDefinition) {
super(name);
this.tableDef = orderedTableDefinition;
}
@Override
public DatasetSpecification configure(String instanceName, DatasetProperties properties) {
return DatasetSpecification.builder(instanceName, getName())
.properties(properties.getProperties())
.datasets(tableDef.configure("ext-schema-table", properties))
.build();
}
@Override
public DatasetAdmin getAdmin(DatasetContext datasetContext, DatasetSpecification spec,
ClassLoader classLoader) throws IOException {
return tableDef.getAdmin(datasetContext, spec.getSpecification("ext-schema-table"), classLoader);
}
@Override
public ExtensiveSchemaTable getDataset(DatasetContext datasetContext, DatasetSpecification spec,
Map<String, String> arguments, ClassLoader classLoader) throws IOException {
Table table = tableDef.getDataset(datasetContext, spec.getSpecification("ext-schema-table"), arguments,
classLoader);
return new ExtensiveSchemaTable(spec.getName(), table);
}
/**
* Extensive schema table.
*/
public static class ExtensiveSchemaTable extends AbstractDataset implements RecordScannable<ExtensiveSchema> {
static final byte[] COL = new byte[] {'c', 'o', 'l', '1'};
private final Table table;
public ExtensiveSchemaTable(String instanceName, Table table) {
super(instanceName, table);
this.table = table;
}
public void put(String key, ExtensiveSchema value) throws Exception {
table.put(Bytes.toBytes(key), COL, Bytes.toBytes(GSON.toJson(value)));
}
public ExtensiveSchema get(String key) throws Exception {
return GSON.fromJson(Bytes.toString(table.get(Bytes.toBytes(key), COL)), ExtensiveSchema.class);
}
@Override
public Type getRecordType() {
return ExtensiveSchema.class;
}
@Override
public List<Split> getSplits() {
return table.getSplits();
}
@Override
public RecordScanner<ExtensiveSchema> createSplitRecordScanner(Split split) {
return Scannables.splitRecordScanner(table.createSplitReader(split), RECORD_MAKER);
}
}
/**
* Custom Type.
*/
public static class Value {
private final String s;
private final int i;
public Value(String s, int i) {
this.s = s;
this.i = i;
}
}
/**
* Extensive schema.
*/
public static class ExtensiveSchema {
// Primitive types (and string)
private final String s;
private final int i;
private final float f;
private final double d;
private final long l;
private final byte b;
private final boolean bo;
private final short sh;
// Arrays
private final int[] iArr;
private final float[] fArr;
private final double[] dArr;
private final long[] lArr;
private final byte[] bArr;
private final boolean[] boArr;
private final short[] shArr;
private final String[] sArr;
// Lists
private final List<Integer> iList;
private final List<Float> fList;
private final List<Double> dList;
private final List<Long> lList;
private final List<Byte> bList;
private final List<Boolean> boList;
private final List<Short> shList;
private final List<String> sList;
// Maps
private final Map<String, Integer> stoiMap;
private final Map<Float, Double> ftodMap;
private final Map<Long, Byte> ltobMap;
private final Map<Boolean, Short> botoshMap;
// Custom type
private final Value v;
private final Value[] vArr;
private final List<Value> vList;
private final Map<String, Value> stovMap;
// Transient and static fields - they shouldn't be included in the schema
private transient int t = 0;
private static int st = 80;
// Reference to itself
// TODO fix infinite loop
// private ExtensiveSchema ext;
public ExtensiveSchema(String s, int i, float f, double d, long l, byte b, boolean bo, short sh, int[] iArr,
float[] fArr, double[] dArr, long[] lArr, byte[] bArr, boolean[] boArr, short[] shArr,
String[] sArr, List<Integer> iList, List<Float> fList, List<Double> dList, List<Long> lList,
List<Byte> bList, List<Boolean> boList, List<Short> shList, List<String> sList,
Map<String, Integer> stoiMap, Map<Float, Double> ftodMap, Map<Long, Byte> ltobMap,
Map<Boolean, Short> botoshMap, Value v, Value[] vArr, List<Value> vList,
Map<String, Value> stovMap) {
this.s = s;
this.i = i;
this.f = f;
this.d = d;
this.l = l;
this.b = b;
this.bo = bo;
this.sh = sh;
this.iArr = iArr;
this.fArr = fArr;
this.dArr = dArr;
this.lArr = lArr;
this.bArr = bArr;
this.boArr = boArr;
this.shArr = shArr;
this.sArr = sArr;
this.iList = iList;
this.fList = fList;
this.dList = dList;
this.lList = lList;
this.bList = bList;
this.boList = boList;
this.shList = shList;
this.sList = sList;
this.stoiMap = stoiMap;
this.ftodMap = ftodMap;
this.ltobMap = ltobMap;
this.botoshMap = botoshMap;
this.v = v;
this.vArr = vArr;
this.vList = vList;
this.stovMap = stovMap;
}
public void setExt(ExtensiveSchema ext) {
// this.ext = ext;
}
}
/**
* ExtensiveSchemaTableModule.
*/
public static class ExtensiveSchemaTableModule implements DatasetModule {
@Override
public void register(DatasetDefinitionRegistry registry) {
DatasetDefinition<Table, DatasetAdmin> table = registry.get("table");
ExtensiveSchemaTableDefinition extensiveSchemaTable =
new ExtensiveSchemaTableDefinition("ExtensiveSchemaTable", table);
registry.add(extensiveSchemaTable);
}
}
private static final Scannables.RecordMaker<byte[], Row, ExtensiveSchema> RECORD_MAKER =
new Scannables.RecordMaker<byte[], Row, ExtensiveSchema>() {
@Override
public ExtensiveSchema makeRecord(byte[] key, Row row) {
return GSON.fromJson(Bytes.toString(row.get(ExtensiveSchemaTable.COL)), ExtensiveSchema.class);
}
};
}