/*******************************************************************************
* /***
* *
* * Copyright 2013 Netflix, 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 com.netflix.paas.dao.meta;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.thrift.CqlResult;
import org.apache.cassandra.thrift.CqlRow;
import org.apache.cassandra.transport.messages.ResultMessage;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ColumnDefinitions;
import com.datastax.driver.core.ColumnDefinitions.Definition;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.exceptions.AlreadyExistsException;
import com.datastax.driver.core.exceptions.DriverException;
import com.google.inject.Inject;
import com.netflix.paas.json.JsonObject;
import com.netflix.paas.meta.dao.MetaDao;
import com.netflix.paas.meta.entity.Entity;
import com.netflix.paas.meta.entity.PaasDBEntity;
import com.netflix.paas.meta.entity.PaasTableEntity;
import com.netflix.paas.util.Pair;
import static com.datastax.driver.core.querybuilder.QueryBuilder.*;
public class CqlMetaDaoImpl implements MetaDao{
private Cluster cluster;
private Session session;
private static boolean schemaCreated = false;
private static final String metaks = "paasmetaks";
private static final String metacf = "metacf";
@Inject
public CqlMetaDaoImpl(Cluster cluster) {
this.cluster = cluster;
this.session = this.cluster.connect();
maybeCreateMetaSchema();
}
@Override
public void writeMetaEntity(Entity entity) {
//if (entity instanceof PaasDBEntity) {
//implies its a create request
//insert into the meta some values for this dbentity
//wait for creation of the actual keyspace
try {
session.execute(String.format(PaasUtils.INSERT_FORMAT, metaks+"."+metacf, entity.getRowKey(),entity.getName(),entity.getPayLoad()));
} catch (AlreadyExistsException e) {
// It's ok, ignore
}
//}
if (entity instanceof PaasTableEntity) {
//first create/check if schema db exists
PaasTableEntity tableEnt = (PaasTableEntity)entity;
try {
String schemaName = tableEnt.getSchemaName();
session.execute(String.format(PaasUtils.CREATE_KEYSPACE_SIMPLE_FORMAT, schemaName, 1));
} catch (AlreadyExistsException e) {
// It's ok, ignore
}
//if schema/db already exists now create the table
String query = BuildQuery(tableEnt);
Print(query);
session.execute(query);
//List<String> primaryKeys = entity.getPrimaryKey();
}
}
public void writeRow(String db, String table,JsonObject rowObj) {
String query = BuildRowInsertQuery(db, table, rowObj);
Print(query);
session.execute(query);
}
private String BuildRowInsertQuery(String db, String table, JsonObject rowObj) {
// TODO Auto-generated method stub
String columns = rowObj.getString("columns");
String values = rowObj.getString("values");
return "INSERT INTO"+" "+db+"."+table+"("+columns+")"+" VALUES("+values+");";
}
private void Print(String str) {
// TODO Auto-generated method stub
System.out.println(str);
}
private String BuildQuery(PaasTableEntity tableEnt) {
// TODO Auto-generated method stub
String schema = tableEnt.getSchemaName();
String tableName = tableEnt.getName();
List<Pair<String, String>> columns = tableEnt.getColumns();
String primary = tableEnt.getPrimarykey();
String colStrs = "";
for (Pair<String, String> colPair:columns) {
colStrs = colStrs+colPair.getRight()+" "+colPair.getLeft()+", ";
}
String primarykeys = tableEnt.getPrimarykey();
String PRIMARYSTR = "PRIMARY KEY("+primarykeys+")";
return "CREATE TABLE "+schema+"."+tableName+" ("+colStrs+" "+PRIMARYSTR+");";
}
public void maybeCreateMetaSchema() {
try {
if (schemaCreated)
return;
try {
session.execute(String.format(PaasUtils.CREATE_KEYSPACE_SIMPLE_FORMAT, metaks, 1));
} catch (AlreadyExistsException e) {
// It's ok, ignore
}
session.execute("USE " + metaks);
for (String tableDef : getTableDefinitions()) {
try {
session.execute(tableDef);
} catch (AlreadyExistsException e) {
// It's ok, ignore
}
}
schemaCreated = true;
} catch (DriverException e) {
throw e;
}
}
protected Collection<String> getTableDefinitions() {
// String sparse = "CREATE TABLE sparse (\n"
// + " k text,\n"
// + " c1 int,\n"
// + " c2 float,\n"
// + " l list<text>,\n"
// + " v int,\n"
// + " PRIMARY KEY (k, c1, c2)\n"
// + ");";
//
// String st = "CREATE TABLE static (\n"
// + " k text,\n"
// + " i int,\n"
// + " m map<text, timeuuid>,\n"
// + " v int,\n"
// + " PRIMARY KEY (k)\n"
// + ");";
//
// String compactStatic = "CREATE TABLE compact_static (\n"
// + " k text,\n"
// + " i int,\n"
// + " t timeuuid,\n"
// + " v int,\n"
// + " PRIMARY KEY (k)\n"
// + ") WITH COMPACT STORAGE;";
//similar to old paas.db table, contains only the metadata about the paas entities
String metaDynamic = "CREATE TABLE metacf (\n"
+ " key text,\n"
+ " column1 text,\n"
+ " value text,\n"
+ " PRIMARY KEY (key, column1)\n"
+ ") WITH COMPACT STORAGE;";
// String compactComposite = "CREATE TABLE compact_composite (\n"
// + " k text,\n"
// + " c1 int,\n"
// + " c2 float,\n"
// + " c3 double,\n"
// + " v timeuuid,\n"
// + " PRIMARY KEY (k, c1, c2, c3)\n"
// + ") WITH COMPACT STORAGE;";
// String withOptions = "CREATE TABLE with_options (\n"
// + " k text,\n"
// + " i int,\n"
// + " PRIMARY KEY (k)\n"
// + ") WITH read_repair_chance = 0.5\n"
// + " AND dclocal_read_repair_chance = 0.6\n"
// + " AND replicate_on_write = true\n"
// + " AND gc_grace_seconds = 42\n"
// + " AND bloom_filter_fp_chance = 0.01\n"
// + " AND caching = ALL\n"
// + " AND comment = 'My awesome table'\n"
// + " AND compaction = { 'class' : 'org.apache.cassandra.db.compaction.LeveledCompactionStrategy', 'sstable_size_in_mb' : 15 }\n"
// + " AND compression = { 'sstable_compression' : 'org.apache.cassandra.io.compress.SnappyCompressor', 'chunk_length_kb' : 128 };";
List<String> allDefs = new ArrayList<String>();
allDefs.add(metaDynamic);
return allDefs;
}
@Override
public Entity readMetaEntity(String rowKey) {
// TODO Auto-generated method stub
return null;
}
@Override
public String listRow(String db, String table, String keycol, String key) {
// TODO Auto-generated method stub
String query = select().all().from(db, table).where(eq(keycol,key)).getQueryString();
ResultSet rs = session.execute(query);
return convertResultSet(rs);
}
private String convertResultSet(ResultSet rs) {
// TODO Auto-generated method stub
String colStr = "";
String rowStr = "";
JsonObject response = new JsonObject();
List<Row> rows = rs.all();
if (!rows.isEmpty() && rows.size()==1) {
rowStr = rows.get(0).toString();
}
ColumnDefinitions colDefs = rs.getColumnDefinitions();
colStr = colDefs.toString();
response.putString("columns", colStr.substring(8,colStr.length()-1));
response.putString("values", rowStr.substring(4,rowStr.length()-1));
return response.toString();
// for (Row ro:rows) {
// Print(ro.toString());
//// ro.getColumnDefinitions()
// }
// return null;
// if (rm.kind == ResultMessage.Kind.ROWS) {
// //ToDo maybe processInternal
// boolean bSwitch = true;
// if (bSwitch) {
// ResultMessage.Rows cqlRows = (ResultMessage.Rows) rm;
// List<ColumnSpecification> columnSpecs = cqlRows.result.metadata.names;
//
// for (List<ByteBuffer> row : cqlRows.result.rows) {
// Map<String,Object> map = new HashMap<String,Object>();
// int i = 0;
// for (ByteBuffer bytes : row) {
// ColumnSpecification specs = columnSpecs.get(i++);
// if (specs.name!=null && specs.type!=null && bytes!=null && bytes.hasRemaining()) {
// System.out.println("name = "+specs.name.toString()+" ,type= "+specs.type.compose(bytes));
// map.put(specs.name.toString(), specs.type.compose(bytes));
// }
// }
// returnRows.add(map);
// }
// } else {
// boolean convert = true;;
// CqlResult result = rm.toThriftResult();
// List<CqlRow> rows = result.getRows();
// for (CqlRow row: rows) {
// List<org.apache.cassandra.thrift.Column> columns = row.getColumns();
// for (org.apache.cassandra.thrift.Column c: columns){
// HashMap<String,Object> m = new HashMap<String,Object>();
// if (convert) {
// m.put("name" , TypeHelper.getCqlTyped(result.schema.name_types.get(c.name), c.name) );
// m.put("value" , TypeHelper.getCqlTyped(result.schema.name_types.get(c.name), c.value) );
// } else {
// m.put("value", TypeHelper.getBytes(c.value));
// m.put("name", TypeHelper.getBytes(c.name));
// }
// returnRows.add(m);
// }
// }
// }
// }
// JsonObject response = new JsonObject();
// JsonArray array = new JsonArray();
// for (Map<String,Object> m : returnRows) {
// array.add(new JsonObject(m));
// }
// response.putString(Long.toString(counter.incrementAndGet()), "OK");
// response.putArray(Long.toString(counter.incrementAndGet()), array);
// String testQry = "CREATE KEYSPACE testdb WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor': 1};";
//// create("testdb",1);
// return response.toString();
// return null;
// }
}
}