package com.freedomotic.plugins.devices.persistence.model;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericData.Record;
import org.apache.avro.generic.GenericRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.freedomotic.app.Freedomotic;
import com.freedomotic.plugins.devices.persistence.cassandra.CassandraCluster;
import com.freedomotic.plugins.devices.persistence.model.avro.FreedomoticData;
import com.freedomotic.plugins.devices.persistence.model.avro.Property;
import com.twitter.bijection.Injection;
import com.twitter.bijection.avro.GenericAvroCodecs;
/**
* This class models the persistence of Freedomotic Data
*/
public class FreedomoticDataDAO extends CassandraDAO {
/** The Constant LOG. */
private final static Logger LOG = LoggerFactory.getLogger(FreedomoticDataDAO.class.getName());
/**
* Instantiates a new dao.
*
* @param cluster the cluster
*/
public FreedomoticDataDAO(CassandraCluster cluster) {
super(cluster);
}
/** The Constant freedomotic schema. */
private static final Schema freedomoticDataSchema = FreedomoticData.getClassSchema();
private static final Schema propertySchema = Property.getClassSchema();
/** The record injection to serialize AVRO entries. */
private final Injection<GenericRecord, byte[]> recordInjection = GenericAvroCodecs.toBinary(freedomoticDataSchema);
/**
* This returns the list of all the data currently persisted on the cluster.
* @return
*/
public List<SerializedPersistedData> getPersistedData() {
Session session = getCluster().getSessionWithFreedomoticKeyspace();
try {
List<SerializedPersistedData> result = new ArrayList<SerializedPersistedData>();
ResultSet resultSet = session.execute(getCluster().getSelectStatement().getQueryString());
for(Row row:resultSet.all()) {
UUID persistedId = row.get("id", UUID.class);
String datatype = row.getString("datatype");
String schema = row.get("avro_schema", String.class);
byte[] binaryContent = row.getBytes("data").array();
Date timestamp = row.get("persistence_timestamp", Date.class);
UUID freedomoticInstanceId = row.get("freedomoticInstance", UUID.class);
result.add(new SerializedPersistedData(persistedId, datatype, schema, binaryContent, timestamp, freedomoticInstanceId));
}
return result;
} catch (Exception e) {
LOG.error("Error while retrieving data from Cassandra, Sorry!", e);
return new ArrayList<SerializedPersistedData>();
} finally {
session.close();
}
}
private boolean persistFreedomoticData(String type, String data_uuid, String name, Long timestamp, Properties properties) {
GenericData.Record freedomoticRecord = new Record(freedomoticDataSchema);
freedomoticRecord.put("uuid", data_uuid);
freedomoticRecord.put("name", name);
freedomoticRecord.put("datetime", timestamp);
freedomoticRecord.put("properties", this.retrievePropertiesToSerialize(properties));
Session session = getCluster().getSessionWithFreedomoticKeyspace();
try {
ResultSet resultSet = session.execute(
getCluster().getInsertStatement()
.bind(
UUID.fromString(data_uuid),
type,
ByteBuffer.wrap(recordInjection.apply(freedomoticRecord)),
freedomoticDataSchema.toString(),
Calendar.getInstance().getTime(),
Freedomotic.getInstanceIdAsUUID()));
boolean dataGotInserted = resultSet.one().getBool("[applied]");
if(dataGotInserted)
return true;
else {
LOG.warn("The data identified by {} has already been persisted", data_uuid);
return false;
}
} catch (Exception e) {
LOG.error("Error while persisting an data on Cassandra, so {} has not been persisted. Sorry!", data_uuid);
e.printStackTrace();
return false;
} finally {
session.close();
}
}
/**
* Persist event.
*
* @param event_uuid, the identifier of the event to be persisted
* @param name the name of the event
* @param timestamp the timestamp of the event
* @param properties, the list of properties to serialize.
* @return true, if persistence goes ok, false otherwise
*/
public boolean persistEvent(String event_uuid, String name, Long timestamp, Properties properties) {
return this.persistFreedomoticData("event", event_uuid, name, timestamp, properties);
}
/**
* Persist command.
*
* @param command_uuid, the identifier of the command to be persisted
* @param name the name of the command
* @param timestamp the timestamp of the command
* @param properties, the list of properties to serialize.
* @return true, if persistence goes ok, false otherwise
*/
public boolean persistCommand(String event_uuid, String name, Long timestamp, Properties properties) {
return this.persistFreedomoticData("command", event_uuid, name, timestamp, properties);
}
private List<GenericData.Record> retrievePropertiesToSerialize(Properties properties) {
List<GenericData.Record> props = new ArrayList<GenericData.Record>(properties.size());
for(String propertyName:properties.stringPropertyNames()) {
GenericData.Record property = new Record(propertySchema);
property.put("key", propertyName);
property.put("value", properties.getProperty(propertyName));
props.add(property);
}
return props;
}
}