/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package org.apache.usergrid.persistence.core.datastax;
import com.datastax.driver.core.DataType;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Inject;
import org.apache.usergrid.persistence.core.CassandraFig;
import org.apache.usergrid.persistence.core.datastax.impl.TableDefinitionImpl;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
public class CQLUtils {
private final static ObjectMapper mapper = new ObjectMapper();
static String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS";
static String ALTER_TABLE = "ALTER TABLE";
static String COMPOSITE_TYPE = "'org.apache.cassandra.db.marshal.DynamicCompositeType(a=>org.apache.cassandra.db.marshal.AsciiType,A=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.AsciiType),b=>org.apache.cassandra.db.marshal.BytesType,B=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.BytesType),i=>org.apache.cassandra.db.marshal.IntegerType,I=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.IntegerType),l=>org.apache.cassandra.db.marshal.LongType,L=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.LongType),s=>org.apache.cassandra.db.marshal.UTF8Type,S=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.UTF8Type),t=>org.apache.cassandra.db.marshal.TimeUUIDType,T=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.TimeUUIDType),u=>org.apache.cassandra.db.marshal.UUIDType,U=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.UUIDType),x=>org.apache.cassandra.db.marshal.LexicalUUIDType,X=>org.apache.cassandra.db.marshal.ReversedType(org.apache.cassandra.db.marshal.LexicalUUIDType))'";
@Inject
public CQLUtils ( ) {
}
public static String getFormattedReplication(
String strategy, String strategyOptions) throws JsonProcessingException {
Map<String, String> replicationSettings = new HashMap<>();
replicationSettings.put("class", strategy);
String[] strategyOptionsSplit = strategyOptions.split(",");
for ( String option : strategyOptionsSplit){
String[] splitOptions = option.split(":");
replicationSettings.put(splitOptions[0], splitOptions[1]);
}
return mapper.writeValueAsString(replicationSettings).replace("\"", "'");
}
public static String getMapAsCQLString(Map<String, Object> map) throws JsonProcessingException {
return mapper.writeValueAsString(map).replace("\"", "'");
}
public static String quote( String value ){
return "\"" + value + "\"";
}
public static String unquote( String value ) {
return value.replace("\"", "");
}
public static String spaceSeparatedKeyValue(Map<String, ?> columns){
StringJoiner columnsSchema = new StringJoiner(",");
columns.forEach( (key, value) -> {
if( value == DataType.Name.CUSTOM ){
columnsSchema.add(key+" "+COMPOSITE_TYPE);
}else {
columnsSchema.add(key + " " + String.valueOf(value));
}
});
return columnsSchema.toString();
}
public static String getCachingOptions(
CassandraFig cassandraFig, TableDefinitionImpl.CacheOption cacheOption) throws JsonProcessingException {
// Cassandra 2.0 and below has a different CQL syntax for caching
if( Double.parseDouble( cassandraFig.getVersion() ) <= 2.0 ){
return quote( getLegacyCacheValue( cacheOption ) );
} else {
return getCacheValue( cacheOption );
}
}
public static String getCacheValue( TableDefinitionImpl.CacheOption cacheOption ) throws JsonProcessingException {
Map<String, Object> cacheValue = new HashMap<>(2);
switch (cacheOption) {
case ALL:
cacheValue.put("keys", "ALL");
cacheValue.put("rows_per_partition", "ALL");
break;
case KEYS:
cacheValue.put("keys", "ALL");
cacheValue.put("rows_per_partition", "NONE");
break;
case ROWS:
cacheValue.put("keys", "NONE");
cacheValue.put("rows_per_partition", "ALL");
break;
case NONE:
cacheValue.put("keys", "NONE");
cacheValue.put("rows_per_partition", "NONE");
break;
default:
cacheValue.put("keys", "NONE");
cacheValue.put("rows_per_partition", "NONE");
break;
}
return getMapAsCQLString( cacheValue );
}
public static String getLegacyCacheValue( TableDefinitionImpl.CacheOption cacheOption ){
String cacheValue;
switch (cacheOption) {
case ALL:
cacheValue = "all";
break;
case KEYS:
cacheValue = "keys_only";
break;
case ROWS:
cacheValue = "rows_only";
break;
case NONE:
cacheValue = "none";
break;
default:
cacheValue = "none";
break;
}
return cacheValue;
}
/**
* Below functions borrowed from Astyanax until the schema is re-written to be more CQL friendly
*/
public static int getShortLength(ByteBuffer bb) {
int length = (bb.get() & 255) << 8;
return length | bb.get() & 255;
}
public static ByteBuffer getBytes(ByteBuffer bb, int length) {
ByteBuffer copy = bb.duplicate();
copy.limit(copy.position() + length);
bb.position(bb.position() + length);
return copy;
}
public static ByteBuffer getWithShortLength(ByteBuffer bb) {
int length = getShortLength(bb);
return getBytes(bb, length);
}
}