/*************************************************************************
* (c) Copyright 2017 Hewlett Packard Enterprise Development Company LP
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
************************************************************************/
package com.eucalyptus.portal.awsusage;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session;
import com.eucalyptus.cassandra.common.CassandraComponent;
import com.eucalyptus.cassandra.common.CassandraKeyspaceSpecification;
import com.eucalyptus.cassandra.common.CassandraPersistence;
import com.eucalyptus.cassandra.common.util.CqlUtil;
import com.eucalyptus.configurable.ConfigurableClass;
import com.eucalyptus.configurable.ConfigurableField;
import com.eucalyptus.configurable.ConfigurableProperty;
import com.eucalyptus.configurable.ConfigurablePropertyException;
import com.eucalyptus.configurable.PropertyChangeListener;
import com.eucalyptus.util.Exceptions;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.List;
import java.util.function.Function;
/**
* Created by ethomas on 11/22/16.
*/
@CassandraKeyspaceSpecification( "eucalyptus_billing" )
@ConfigurableClass(root = "services.billing", description = "Parameters controlling billing service")
public class CassandraSessionManager implements CassandraComponent {
// TODO: this is a temporary class and needs to be replaced once the cassandra framework is committed to master.
private static final Logger LOG = Logger.getLogger(CassandraSessionManager.class);
@ConfigurableField(
initial = "postgres",
description = "The db to use"
)
public static volatile String DB_TO_USE = "postgres";
@ConfigurableField(
initial = "127.0.0.1",
description = "The host for cassandra",
changeListener = CassandraSessionManager.ChangeListener.class )
public static volatile String CASSANDRA_HOST = "127.0.0.1";
private static Cluster cluster = null;
private static Session session = null;
private static synchronized void initCluster() {
initCluster(CassandraSessionManager.CASSANDRA_HOST);
}
private static synchronized void initCluster(String contactPoint) {
if (session != null) {
session.close();
session = null;
}
if (cluster != null) {
cluster.close();
cluster = null;
}
LOG.info("Trying to connect to the cluster " + contactPoint);
List<String> contactPoints = Lists.newArrayList();
for (String s: Splitter.on(",").omitEmptyStrings().split(contactPoint)) {
contactPoints.add(s);
}
cluster = Cluster.builder().addContactPoints(contactPoints.toArray(new String[0])).build();
session = cluster.connect();
// create new keyspace/tables (should not do here) TODO: move
session.execute("CREATE KEYSPACE IF NOT EXISTS eucalyptus_billing " +
"WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}; ");
session.execute("USE eucalyptus_billing;");
try {
final String cql = Resources.toString(
Resources.getResource("2017-03-28-eucalyptus-billing-base.cql"),
StandardCharsets.UTF_8 );
CqlUtil.splitCql( cql ).forEach( session::execute );
} catch ( final IOException | ParseException e ) {
throw Exceptions.toUndeclared( e );
}
}
private static synchronized Session getSession() {
if (session == null) {
initCluster();
}
return session;
}
/**
* Perform work using a datastax session in a callback.
*/
public static <R> R doWithSession(
final Function<? super Session,? extends R> callbackFunction
) {
if ( "cassandra".equals( DB_TO_USE ) ) {
return callbackFunction.apply( getSession( ) );
} else {
return CassandraPersistence.doWithSession( "eucalyptus_billing", callbackFunction );
}
};
public static class ChangeListener implements PropertyChangeListener {
@Override
public void fireChange(ConfigurableProperty t, Object newValue) throws ConfigurablePropertyException {
try {
initCluster((String) newValue);
} catch (Exception e) {
throw new ConfigurablePropertyException(e.getMessage());
}
}
}
}