All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.astyanax.cql.schema.CqlKeyspaceDefinitionImpl Maven / Gradle / Ivy

package com.netflix.astyanax.cql.schema;

import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
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.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.netflix.astyanax.connectionpool.OperationResult;
import com.netflix.astyanax.cql.CqlOperationResultImpl;
import com.netflix.astyanax.ddl.ColumnFamilyDefinition;
import com.netflix.astyanax.ddl.FieldMetadata;
import com.netflix.astyanax.ddl.KeyspaceDefinition;
import com.netflix.astyanax.ddl.SchemaChangeResult;

/**
 * Impl for {@link KeyspaceDefinition} using the java driver. 
 * 
 * @author poberai
 *
 */
public class CqlKeyspaceDefinitionImpl implements KeyspaceDefinition {

	private static final Logger Log = LoggerFactory.getLogger(CqlKeyspaceDefinitionImpl.class);
	
	private final Session session; 
	private boolean alterKeyspace; 
	private final Map options = new HashMap();
	private final List cfDefList = new ArrayList();
	
	public CqlKeyspaceDefinitionImpl(Session session) {
		this.session = session;
	}

	public CqlKeyspaceDefinitionImpl(Session session, Map input) {
		this.session = session;
		checkOptionsMap(input);
	}

	public CqlKeyspaceDefinitionImpl(Session session, Properties props) {
		this.session = session;
		checkOptionsMap(propertiesToMap(props));
	}

	public CqlKeyspaceDefinitionImpl(Session session, Row row) {
		
		this.session = session; 
		this.setName(row.getString("keyspace_name"));
		this.setStrategyClass(row.getString("strategy_class"));
		this.setStrategyOptionsMap(parseStrategyOptions(row.getString("strategy_options")));
		this.options.put("durable_writes", row.getBool("durable_writes"));
	}
	
	public CqlKeyspaceDefinitionImpl alterKeyspace() {
		alterKeyspace = true;
		return this;
	}


	@Override
	public CqlKeyspaceDefinitionImpl setName(String name) {
		this.options.put("name", name.toLowerCase());
		return this;
	}

	@Override
	public String getName() {
		return (String) options.get("name");
	}

	@Override
	public CqlKeyspaceDefinitionImpl setStrategyClass(String strategyClass) {
		getOrCreateReplicationMap().put("class", strategyClass);
		return this;
	}

	@Override
	public String getStrategyClass() {
		return (String) getOrCreateReplicationMap().get("class");
	}

	@Override
	public CqlKeyspaceDefinitionImpl setStrategyOptions(Map strategyOptions) {
		getOrCreateReplicationMap().putAll(strategyOptions);
		return this;
	}
	
	public CqlKeyspaceDefinitionImpl setStrategyOptionsMap(Map strategyOptions) {
		getOrCreateReplicationMap().putAll(strategyOptions);
		return this;
	}

	
	@Override
	public CqlKeyspaceDefinitionImpl addStrategyOption(String name, String value) {
		this.getOrCreateReplicationMap().put(name, value);
		return this;
	}

	@Override
	public Map getStrategyOptions() {
		Map map = new HashMap();
		Map repMap = getOrCreateReplicationMap();
		for (String key : repMap.keySet()) {
			map.put(key, (String) repMap.get(key));
		}
		return map;
	}

	@Override
	public List getColumnFamilyList() {
		Statement query = QueryBuilder.select().all()
				.from("system", "schema_columnfamilies")
				.where(eq("keyspace_name", getName()));
				
		ResultSet rs = session.execute(query);
		List cfDefs = new ArrayList();
		List rows = rs.all();
		if (rows != null) {
			for (Row row : rows) {
				cfDefs.add(new CqlColumnFamilyDefinitionImpl(session, row));
			}
		}
		return cfDefs;
	}

	@Override
	public ColumnFamilyDefinition getColumnFamily(String columnFamilyName) {
		
		Statement query = QueryBuilder.select().all()
				.from("system", "schema_columnfamilies")
				.where(eq("keyspace_name", getName()))
				.and(eq("columnfamily_name", columnFamilyName.toLowerCase()));

		Row row = session.execute(query).one();
		
		if (row == null) {
			throw new RuntimeException("CF not found: " + columnFamilyName);
		}
		return new CqlColumnFamilyDefinitionImpl(session, row);
	}

	@Override
	public KeyspaceDefinition addColumnFamily(ColumnFamilyDefinition cfDef) {
		CqlColumnFamilyDefinitionImpl cqlCfDef = (CqlColumnFamilyDefinitionImpl) cfDef; 
		cqlCfDef.execute();
		return this;
	}

	@Override
	public Collection getFieldNames() {
		return options.keySet();
	}

	@Override
	public Object getFieldValue(String name) {
		return options.get(name);
	}

	@Override
	public KeyspaceDefinition setFieldValue(String name, Object value) {
		this.options.put(name, value);
		return this;
	}

	@Override
	public Collection getFieldsMetadata() {
		
		List list = new ArrayList();
		
		for (String key : options.keySet()) {
			Object value = options.get(key);
			
			Class clazz = value.getClass();
			
			String name = key.toUpperCase();
			String type = clazz.getSimpleName().toUpperCase();
			boolean isContainer = Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz);
			list.add(new FieldMetadata(name, type, isContainer));
		}
		return list;
	}

	@Override
	public void setFields(Map optionsMap) {
		checkOptionsMap(optionsMap);
	}

	@Override
	public Properties getProperties() throws Exception {
		return mapToProperties(options);
	}

	@Override
	public void setProperties(Properties props) throws Exception {
		options.clear();
		options.putAll(propertiesToMap(props));
	}
	
	
	public OperationResult execute() {
		
		String query = getQuery();

		if (Log.isDebugEnabled()) {
			Log.debug("Query : " + query);
		}
		
		CqlOperationResultImpl result = new CqlOperationResultImpl(session.execute(query), null);
		
		for (CqlColumnFamilyDefinitionImpl cfDef : cfDefList) {
			cfDef.execute();
		}
		
		return result;
	}

	
	private String getQuery() {
		
		String cmd = (alterKeyspace) ? "ALTER" : "CREATE";
		
		StringBuilder sb = new StringBuilder(cmd); 
		sb.append(" KEYSPACE ");
		sb.append(getName());
		
		Map replicationOptions = (Map) options.get("replication");
		appendReplicationOptions(sb, replicationOptions);
		
		Object durableWrites = options.get("durable_writes");
		if (durableWrites != null) {
			sb.append(" AND durable_writes = ").append(durableWrites);
		}
		return sb.toString();
	}
	
	private void appendReplicationOptions(StringBuilder sb, Map replicationOptions) {

		if (replicationOptions == null || replicationOptions.size() == 0) {
			throw new RuntimeException("Missing properties for 'replication'");
		}

		sb.append(" WITH replication = {" );

		Iterator> iter = replicationOptions.entrySet().iterator();
		
		while (iter.hasNext()) {
			
			Entry entry = iter.next();
			sb.append("'").append(entry.getKey()).append("' : '").append(entry.getValue()).append("'");
			if (iter.hasNext()) {
				sb.append(", ");
			}
		}
		
		sb.append("}");
	}
	
	
	private void checkOptionsMap(Map input) {
		
		Object strategyOptions = input.get("strategy_options");
		
		if (strategyOptions == null) {
			Preconditions.checkArgument(input.get("replication") != null, "Invalid CREATE KEYSPACE properties");
			options.clear();
			options.putAll(input);
			
		} else {
			
			// this is an old style map. Convert to the new spec of CREATE KEYSPACE
			options.clear();
			
			Map replicationOptions = new HashMap();
			options.put("replication", replicationOptions);
			
			Map oldStrategyOptions = (Map) input.get("strategy_options");
			replicationOptions.putAll(oldStrategyOptions);

			String strategyClass = (String) input.get("strategy_class");
			replicationOptions.put("class", strategyClass);
		}
	}
	
	private Map getOrCreateReplicationMap() {
		Map replicationMap = (Map) options.get("replication");
		if (replicationMap == null) {
			replicationMap = new HashMap();
			options.put("replication", replicationMap);
		}
		return replicationMap;
	}
	
	private static Map propertiesToMap(Properties props) {
		Map root = Maps.newTreeMap();
		for (Entry prop : props.entrySet()) {
			String[] parts = StringUtils.split((String)prop.getKey(), ".");
			Map node = root;
			for (int i = 0; i < parts.length - 1; i++) {
				if (!node.containsKey(parts[i])) {
					node.put(parts[i], new LinkedHashMap());
				}
				node = (Map)node.get(parts[i]);
			}
			node.put(parts[parts.length-1], (String)prop.getValue());
		}
		return root;
	}


	private static Properties mapToProperties(Map map) {
		
		Properties props = new Properties();
		addProperties(props, null, map);
		return props;
	}
	
	private static void addProperties(Properties props, String prefix, Map subMap) {
		
		for (Entry entry : subMap.entrySet()) {
			
			String key = (prefix != null) ? prefix + "." + entry.getKey() : entry.getKey();
			if (entry.getValue() instanceof Map) {
				addProperties(props, key, (Map) entry.getValue());
			} else {
				props.put(key, entry.getValue().toString());
			}
		}
	}
	
	private Map parseStrategyOptions(String jsonString) {
		
		if (jsonString == null || jsonString.isEmpty()) {
			return null;
		}
		
		Map map = new HashMap();
		try {
			JSONObject json = new JSONObject(jsonString);
			Iterator iter = json.keys();
			while (iter.hasNext()) {
				String key = iter.next();
				Object obj = json.get(key);
				map.put(key, obj);
			}
			return map;
		} catch (JSONException e) {
			throw new RuntimeException(e);
		}
	}
	

	public String toString() {
		return "CqlKeyspaceDefinition=[ " + options.toString() + " ]";
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy