Java tutorial
/*- * ============LICENSE_START======================================================= * SDC * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * 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. * ============LICENSE_END========================================================= */ package org.openecomp.sdc.be.dao.cassandra.schema; import com.datastax.driver.core.*; import com.datastax.driver.core.schemabuilder.Alter; import com.datastax.driver.core.schemabuilder.Create; import com.datastax.driver.core.schemabuilder.SchemaBuilder; import com.datastax.driver.core.schemabuilder.SchemaStatement; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.config.*; import org.openecomp.sdc.be.config.Configuration; import org.openecomp.sdc.be.resources.data.auditing.AuditingTypesConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; import java.security.NoSuchAlgorithmException; import java.util.*; import java.util.stream.Collectors; public class SdcSchemaBuilder { /** * creat key space statment for SimpleStrategy */ final static String CREATE_KEYSPACE_SIMPLE_STRATEGY = "CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class':'SimpleStrategy', %s};"; /** * creat key space statment for NetworkTopologyStrategy */ final static String CREATE_KEYSPACE_NETWORK_TOPOLOGY_STRATEGY = "CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class':'NetworkTopologyStrategy', %s};"; private static Logger log = LoggerFactory.getLogger(SdcSchemaBuilder.class.getName()); /** * the method creates all keyspaces, tables and indexes in case they do not * already exist. the method can be run multiple times. the method uses the * internal enums and external configuration for its operation * * @return true if the create operation was successful */ public static boolean createSchema() { Cluster cluster = null; Session session = null; try { log.info("creating Schema for Cassandra."); cluster = createCluster(); if (cluster == null) { return false; } session = cluster.connect(); List<KeyspaceMetadata> keyspacesMetadateFromCassandra = cluster.getMetadata().getKeyspaces(); if (keyspacesMetadateFromCassandra == null) { log.debug("filed to retrive a list of keyspaces from cassndra"); return false; } log.debug("retrived Cassndra metadata."); Map<String, Map<String, List<String>>> cassndraMetadata = parseKeyspaceMetadata( keyspacesMetadateFromCassandra); Map<String, List<ITableDescription>> schemeData = getSchemeData(); log.info("creating Keyspaces."); for (String keyspace : schemeData.keySet()) { if (!createKeyspace(keyspace, cassndraMetadata, session)) { return false; } Map<String, List<String>> keyspaceMetadate = cassndraMetadata.get(keyspace); createTables(schemeData.get(keyspace), keyspaceMetadate, session); } return true; } catch (Exception e) { log.info("createSchema failed with exception.", e); } finally { if (session != null) { session.close(); } if (cluster != null) { cluster.close(); } } return false; } public static boolean deleteSchema() { Cluster cluster = null; Session session = null; try { log.info("delete Data from Cassandra."); cluster = createCluster(); if (cluster == null) { return false; } session = cluster.connect(); List<KeyspaceMetadata> keyspacesMetadateFromCassandra = cluster.getMetadata().getKeyspaces(); if (keyspacesMetadateFromCassandra == null) { log.debug("filed to retrive a list of keyspaces from cassndra"); return false; } log.debug("retrived Cassndra metadata."); Map<String, Map<String, List<String>>> cassndraMetadata = parseKeyspaceMetadata( keyspacesMetadateFromCassandra); cassndraMetadata.forEach((k, v) -> { if (AuditingTypesConstants.TITAN_KEYSPACE.equals(k)) { // session.execute("") } else if (AuditingTypesConstants.ARTIFACT_KEYSPACE.equals(k)) { } else if (AuditingTypesConstants.AUDIT_KEYSPACE.equals(k)) { } }); System.out.println(cassndraMetadata); return true; } catch (Exception e) { log.info("deleteSchema failed with exception.", e); } finally { if (session != null) { session.close(); } if (cluster != null) { cluster.close(); } } return false; } /** * the method creates the cluster object using the supplied cassandra nodes * in the configuration * * @return cluster object our null in case of an invalid configuration */ private static Cluster createCluster() { List<String> nodes = ConfigurationManager.getConfigurationManager().getConfiguration().getCassandraConfig() .getCassandraHosts(); if (nodes == null) { log.info("no nodes were supplied in configuration."); return null; } log.info("connecting to node:{}.", nodes); Cluster.Builder clusterBuilder = Cluster.builder(); nodes.forEach(host -> clusterBuilder.addContactPoint(host)); clusterBuilder.withMaxSchemaAgreementWaitSeconds(60); boolean authenticate = ConfigurationManager.getConfigurationManager().getConfiguration() .getCassandraConfig().isAuthenticate(); if (authenticate) { String username = ConfigurationManager.getConfigurationManager().getConfiguration().getCassandraConfig() .getUsername(); String password = ConfigurationManager.getConfigurationManager().getConfiguration().getCassandraConfig() .getPassword(); if (username == null || password == null) { log.info("authentication is enabled but username or password were not supplied."); return null; } clusterBuilder.withCredentials(username, password); } boolean ssl = ConfigurationManager.getConfigurationManager().getConfiguration().getCassandraConfig() .isSsl(); if (ssl) { String truststorePath = ConfigurationManager.getConfigurationManager().getConfiguration() .getCassandraConfig().getTruststorePath(); String truststorePassword = ConfigurationManager.getConfigurationManager().getConfiguration() .getCassandraConfig().getTruststorePassword(); if (truststorePath == null || truststorePassword == null) { log.info("ssl is enabled but truststorePath or truststorePassword were not supplied."); return null; } System.setProperty("javax.net.ssl.trustStore", truststorePath); System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword); clusterBuilder.withSSL(); } return clusterBuilder.build(); } /** * the method prcess the metadata retrieved from the cassandra for the * creation of a map conting the names of keyspaces tabls and indexes * already defined in the cassandra keyspacename -> tablename -> list of * indexes info * * @param keyspacesMetadata * cassndra mmetadata * @return a map of maps of lists holding parsed info */ private static Map<String, Map<String, List<String>>> parseKeyspaceMetadata( List<KeyspaceMetadata> keyspacesMetadata) { Map<String, Map<String, List<String>>> cassndraMetadata = keyspacesMetadata.stream() .collect(Collectors.toMap(keyspaceMetadata -> keyspaceMetadata.getName(), keyspaceMetadata -> keyspaceMetadata.getTables().stream() .collect(Collectors.toMap(tableMetadata -> tableMetadata.getName(), tableMetadata -> tableMetadata.getIndexes().stream() .map(indexMetadata -> indexMetadata.getName()) .collect(Collectors.toList()))))); return cassndraMetadata; } /** * the method builds an index name according to a defined logic * <table> * _<column>_idx * * @param table * table name * @param column * column name * @return string name of the index */ private static String createIndexName(String table, String column) { return new StringBuilder().append(table).append("_").append(column).append("_idx").toString(); } /** * the method creats all the tables and indexes thet do not already exist * * @param iTableDescriptions * a list of table description we want to create * @param keyspaceMetadate * the current tables that exist in the cassandra under this * keyspace * @param session * the session object used for the execution of the query. */ private static void createTables(List<ITableDescription> iTableDescriptions, Map<String, List<String>> keyspaceMetadate, Session session) { for (ITableDescription tableDescription : iTableDescriptions) { String tableName = tableDescription.getTableName().toLowerCase(); Map<String, ImmutablePair<DataType, Boolean>> columnDescription = tableDescription .getColumnDescription(); log.info("creating tables:{}.", tableName); if (keyspaceMetadate == null || !keyspaceMetadate.keySet().contains(tableName)) { Create create = SchemaBuilder.createTable(tableDescription.getKeyspace(), tableDescription.getTableName()); for (ImmutablePair<String, DataType> key : tableDescription.primaryKeys()) { create.addPartitionKey(key.getLeft(), key.getRight()); } if (tableDescription.clusteringKeys() != null) { for (ImmutablePair<String, DataType> key : tableDescription.clusteringKeys()) { create.addClusteringColumn(key.getLeft(), key.getRight()); } } for (String columnName : columnDescription.keySet()) { create.addColumn(columnName, columnDescription.get(columnName).getLeft()); } log.trace("exacuting :{}", create.toString()); ResultSet result = session.execute(create); log.info("table:{} created succsesfully.", tableName); } else { log.info("table:{} already exists skiping.", tableName); } List<String> indexNames = (keyspaceMetadate != null ? keyspaceMetadate.get(tableName) : new ArrayList<>()); log.info("table:{} creating indexes.", tableName); for (String columnName : columnDescription.keySet()) { String indexName = createIndexName(tableName, columnName).toLowerCase(); if (columnDescription.get(columnName).getRight()) { if (!indexNames.contains(indexName)) { SchemaStatement creatIndex = SchemaBuilder.createIndex(indexName) .onTable(tableDescription.getKeyspace(), tableName).andColumn(columnName); log.info("executing :{}", creatIndex.toString()); session.execute(creatIndex); log.info("index:{} created succsesfully.", indexName); } else { log.info("index:{} already exists skiping.", indexName); } } } } } /** * the method create the keyspace in case it does not already exists the * method uses configurtion to select the needed replication strategy * * @param keyspace * name of the keyspace we want to create * @param cassndraMetadata * cassndra metadata * @param session * the session object used for the execution of the query. * @return true in case the operation was successful */ private static boolean createKeyspace(String keyspace, Map<String, Map<String, List<String>>> cassndraMetadata, Session session) { List<Configuration.CassandrConfig.KeyspaceConfig> keyspaceConfigList = ConfigurationManager .getConfigurationManager().getConfiguration().getCassandraConfig().getKeySpaces(); log.info("creating keyspace:{}.", keyspace); if (!cassndraMetadata.keySet().contains(keyspace)) { Optional<Configuration.CassandrConfig.KeyspaceConfig> keyspaceConfig = keyspaceConfigList.stream() .filter(keyspaceInfo -> keyspace.equalsIgnoreCase(keyspaceInfo.getName())).findFirst(); if (keyspaceConfig.isPresent()) { Configuration.CassandrConfig.KeyspaceConfig keyspaceInfo = keyspaceConfig.get(); String createKeyspaceQuery = createKeyspaceQuereyString(keyspace, keyspaceInfo); if (createKeyspaceQuery != null) { log.trace("exacuting: {}", createKeyspaceQuery); session.execute(createKeyspaceQuery); log.info("keyspace:{} created.", keyspace); return true; } else { return false; } } else { log.info( "keyspace:{} not present in configuration, no info on replications is available. operation failed.", keyspace); return false; } } else { log.info("keyspace:{} already exists skipping.", keyspace); return true; } } /** * the method retries the schem info from the enums describing the tables * * @return a map of keyspaces to there table info */ private static Map<String, List<ITableDescription>> getSchemeData() { Map<String, List<ITableDescription>> tablesByKeyspace = new HashMap<String, List<ITableDescription>>(); Table[] tables = Table.values(); for (Table table : tables) { String keyspace = table.getTableDescription().getKeyspace().toLowerCase(); List<ITableDescription> list = tablesByKeyspace.get(keyspace); if (list == null) { list = new ArrayList<>(); } list.add(table.getTableDescription()); tablesByKeyspace.put(keyspace, list); } return tablesByKeyspace; } /** * the methoed creates the query string for the given keyspace the methoed * valides the given data according the the requirments of the replication * strategy SimpleStrategy: "CREATE KEYSPACE IF NOT EXISTS * <keyspaceName></keyspaceName> WITH replication = * {'class':'SimpleStrategy', 'replication_factor':2};" SimpleStrategy: * "CREATE KEYSPACE IF NOT EXISTS <keyspaceName></keyspaceName> WITH * replication = {'class':'NetworkTopologyStrategy', 'dc1' : 2 ,dc2 : 2 };" * * @param keyspace * name of the keyspace we want to create * @param keyspaceInfo * configuration info regurding the replication of the keyspace * @return a querey string for the creation of the keyspace */ private static String createKeyspaceQuereyString(String keyspace, Configuration.CassandrConfig.KeyspaceConfig keyspaceInfo) { String query = null; if (ReplicationStrategy.NETWORK_TOPOLOGY_STRATEGY.getName() .equalsIgnoreCase(keyspaceInfo.getReplicationStrategy())) { List<String> dcList = keyspaceInfo.getReplicationInfo(); if (dcList.size() % 2 != 0) { log.error("the supplied replication info is in valid expected dc1,2,dc2,2 etc received:{}", dcList); return query; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < dcList.size(); i = i + 2) { sb.append("'").append(dcList.get(i)).append("'").append(" : ").append(dcList.get(i + 1)); if (i + 2 < dcList.size()) { sb.append(","); } } query = String.format(CREATE_KEYSPACE_NETWORK_TOPOLOGY_STRATEGY, keyspace, sb.toString()); } else if (ReplicationStrategy.SIMPLE_STRATEGY.getName() .equalsIgnoreCase(keyspaceInfo.getReplicationStrategy())) { List<String> dcList = keyspaceInfo.getReplicationInfo(); if (dcList.size() != 1) { log.error("the supplied replication info is in valid expected <number> etc received:{}", dcList); return query; } StringBuilder sb = new StringBuilder(); sb.append("'replication_factor'").append(" : ").append(dcList.get(0)); query = String.format(CREATE_KEYSPACE_SIMPLE_STRATEGY, keyspace, sb.toString()); } else { log.error("the suplied replication Strategy is in valide expacted {}/{} etc recived:{}", ReplicationStrategy.NETWORK_TOPOLOGY_STRATEGY.getName(), ReplicationStrategy.SIMPLE_STRATEGY.getName(), keyspaceInfo.getReplicationStrategy()); } return query; } public enum ReplicationStrategy { NETWORK_TOPOLOGY_STRATEGY("NetworkTopologyStrategy"), SIMPLE_STRATEGY("SimpleStrategy"); public String name; private ReplicationStrategy(String name) { this.name = name; } public String getName() { return name; } } }