package com.freedomotic.plugins.devices.persistence.cassandra; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.KeyspaceMetadata; import com.datastax.driver.core.PreparedStatement; import com.datastax.driver.core.Session; import com.datastax.driver.core.exceptions.NoHostAvailableException; /** * Configuration class to setup and run Cassandra Cluster in Persistence Plugin. * * @author P3trur0, https://flatmap.it */ public final class CassandraCluster { /** Cassandra cluster reference. */ private final Cluster cluster; /** This represents the name of the keyspace to be used, <b>freedomotic</b> by default. */ private String keyspace; /** The configuration properties. */ private final Properties configurationProperties; /** The Constant LOG. */ private final static Logger LOG = LoggerFactory.getLogger(CassandraCluster.class.getName()); /** The table representation. */ private static final CassandraTable freedomoticData; private PreparedStatement insertStatement, selectStatement; static { List<CassandraColumn> tableColumns = new ArrayList<CassandraColumn>(); tableColumns.add(new CassandraColumn("id", "uuid", true)); tableColumns.add(new CassandraColumn("datatype", "varchar")); tableColumns.add(new CassandraColumn("data", "blob")); tableColumns.add(new CassandraColumn("avro_schema", "text")); tableColumns.add(new CassandraColumn("persistence_timestamp", "timestamp")); tableColumns.add(new CassandraColumn("freedomoticInstance","uuid")); freedomoticData = new CassandraTable("freedomotic_data", tableColumns); } /** * Instantiates a new cassandra cluster. * * @param props the properties representing the configuration */ public CassandraCluster(Properties props) { this.configurationProperties = props; String contactPoint = props.getProperty("cassandra.host", "127.0.0.1"); this.keyspace = props.getProperty("cassandra.keyspace", "freedomotic"); LOG.info("Building Cassandra Cluster for host > " + contactPoint); LOG.info("Plugin keyspace is " + keyspace); cluster = Cluster.builder().addContactPoint(contactPoint).build(); } /** * Inits the cluster * * @return true, if successful */ public boolean init() { Session cassandraSession = null; String replicationFactor = configurationProperties.getProperty("cassandra.replicationFactor", "1"); String strategy = configurationProperties.getProperty("cassandra.strategy", "SimpleStrategy"); try { cassandraSession = this.getSession(); if (!this.isKeyspaceCreated()) { this.createFreedomoticKeyspace(cassandraSession, replicationFactor, strategy); } this.prepareFreedomoticStatements(cassandraSession); return true; } catch (Exception e) { LOG.error("Error while creating Cassandra keyspace for freedomotic", e); if (e instanceof NoHostAvailableException) { NoHostAvailableException nha = (NoHostAvailableException) e; for(Map.Entry<InetSocketAddress,Throwable> error: nha.getErrors().entrySet()) LOG.error("Connection error on "+error.getKey().getHostName()+", port n. "+error.getKey().getPort(), error.getValue()); } return false; } finally { if (cassandraSession != null) cassandraSession.close(); } } /** * Creates the freedomotic keyspace on Cassandra * * @param session the session to be use to create the keyspace * @param replicationFactor the replication factor of this cassandra instance. * @param strategy the replication strategy of this instance */ public void createFreedomoticKeyspace(Session session, String replicationFactor, String strategy) { if (replicationFactor == null) replicationFactor = "1"; if (strategy == null) strategy = "SimpleStrategy"; session.execute("CREATE KEYSPACE IF NOT EXISTS " + keyspace + " " + "WITH replication = {'class':'" + strategy + "', 'replication_factor':" + replicationFactor + "};"); session.execute("CREATE TABLE IF NOT EXISTS " + keyspace + "." + freedomoticData.tableToString() + ";"); } /** * This method prepares the statements to perform Cassandra data persistence. * * @param session */ private void prepareFreedomoticStatements(Session session) { insertStatement = session.prepare("INSERT INTO "+keyspace+"."+freedomoticData.getName()+" (id, datatype, data, avro_schema, persistence_timestamp, freedomoticInstance) VALUES (?, ?, ?, ?, ?, ?) IF NOT EXISTS"); selectStatement = session.prepare("SELECT id, datatype, data, avro_schema, persistence_timestamp, freedomoticInstance FROM "+keyspace+"."+freedomoticData.getName()); } /** * It creates and return a generic Cassandra session * * @return the session */ public Session getSession() { return cluster.connect(); } /** * It creates and return the session referring to freedomotic keyspace. * * @return the session referring to freedomotic keyspace */ public Session getSessionWithFreedomoticKeyspace() { return cluster.connect(keyspace); } /** * It releases the cluster resources */ public void releaseResource() { cluster.close(); } /** * Checks if is keyspace created. * * @return true, if is keyspace created */ public boolean isKeyspaceCreated() { KeyspaceMetadata ks = cluster.getMetadata().getKeyspace(keyspace); if (ks == null) return false; else return true; } /** * Gets the freedomotic table. * * @return the freedomotic table */ public static CassandraTable getCassandraTable() { return freedomoticData; } /** * @return the select prepared statement */ public PreparedStatement getSelectStatement() { return selectStatement; } /** * @return the insert prepared statement */ public PreparedStatement getInsertStatement() { return insertStatement; } }