package mil.nga.giat.geowave.core.store.operations.remote.options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.ParametersDelegate;
import mil.nga.giat.geowave.core.cli.api.DefaultPluginOptions;
import mil.nga.giat.geowave.core.cli.api.PluginOptions;
import mil.nga.giat.geowave.core.index.ByteArrayId;
import mil.nga.giat.geowave.core.index.CompoundIndexStrategy;
import mil.nga.giat.geowave.core.index.simple.HashKeyIndexStrategy;
import mil.nga.giat.geowave.core.index.simple.RoundRobinKeyIndexStrategy;
import mil.nga.giat.geowave.core.store.index.CustomIdIndex;
import mil.nga.giat.geowave.core.store.index.PrimaryIndex;
import mil.nga.giat.geowave.core.store.spi.DimensionalityTypeOptions;
import mil.nga.giat.geowave.core.store.spi.DimensionalityTypeProviderSpi;
import mil.nga.giat.geowave.core.store.spi.DimensionalityTypeRegistry;
/**
* This class is responsible for loading index SPI plugins and populating
* parameters delegate with relevant options for that index.
*/
public class IndexPluginOptions extends
DefaultPluginOptions implements
PluginOptions
{
public static final String INDEX_PROPERTY_NAMESPACE = "index";
public static final String DEFAULT_PROPERTY_NAMESPACE = "indexdefault";
private final static Logger LOGGER = LoggerFactory.getLogger(IndexPluginOptions.class);
private String indexType;
@Parameter(names = {
"--indexName"
}, description = "A custom name can be given to this index. Default name will be the based on configuration parameters.")
protected String nameOverride = null;
@Parameter(names = {
"-np",
"--numPartitions"
}, description = "The number of partitions. Default partitions will be 1.")
protected int numPartitions = 1;
@Parameter(names = {
"-ps",
"--partitionStrategy"
}, description = "The partition strategy to use. Default will be none.")
protected PartitionStrategy partitionStrategy = PartitionStrategy.NONE;
// This is the plugin loaded from SPI based on "type"
private DimensionalityTypeProviderSpi indexPlugin = null;
// These are the options loaded from indexPlugin based on "type"
@ParametersDelegate
private DimensionalityTypeOptions indexOptions = null;
/**
* Constructor
*/
public IndexPluginOptions() {
}
@Override
public void selectPlugin(
final String qualifier ) {
// Load the Index options.
indexType = qualifier;
if (qualifier != null) {
indexPlugin = DimensionalityTypeRegistry.getSelectedDimensionalityProvider(qualifier);
if (indexPlugin == null) {
throw new ParameterException(
"Unknown index type specified");
}
indexOptions = indexPlugin.getOptions();
}
else {
indexPlugin = null;
indexOptions = null;
}
}
@Override
public String getType() {
return indexType;
}
public int getNumPartitions() {
return numPartitions;
}
public String getNameOverride() {
return nameOverride;
}
public PartitionStrategy getPartitionStrategy() {
return partitionStrategy;
}
public DimensionalityTypeProviderSpi getIndexPlugin() {
return indexPlugin;
}
public PrimaryIndex createPrimaryIndex() {
final PrimaryIndex index = indexPlugin.createPrimaryIndex();
return wrapIndexWithOptions(
index,
this);
}
private static PrimaryIndex wrapIndexWithOptions(
final PrimaryIndex index,
final IndexPluginOptions options ) {
PrimaryIndex retVal = index;
if ((options.numPartitions > 1) && options.partitionStrategy.equals(PartitionStrategy.ROUND_ROBIN)) {
retVal = new CustomIdIndex(
new CompoundIndexStrategy(
new RoundRobinKeyIndexStrategy(
options.numPartitions),
index.getIndexStrategy()),
index.getIndexModel(),
new ByteArrayId(
index.getId().getString() + "_" + PartitionStrategy.ROUND_ROBIN.name() + "_"
+ options.numPartitions));
}
else if (options.numPartitions > 1) {
// default to round robin partitioning (none is not valid if there
// are more than 1 partition)
if (options.partitionStrategy.equals(PartitionStrategy.NONE)) {
LOGGER
.warn("Partition strategy is necessary when using more than 1 partition, defaulting to 'hash' partitioning.");
}
retVal = new CustomIdIndex(
new CompoundIndexStrategy(
new HashKeyIndexStrategy(
options.numPartitions),
index.getIndexStrategy()),
index.getIndexModel(),
new ByteArrayId(
index.getId().getString() + "_" + PartitionStrategy.HASH.name() + "_"
+ options.numPartitions));
}
if ((options.getNameOverride() != null) && (options.getNameOverride().length() > 0)) {
retVal = new CustomIdIndex(
retVal.getIndexStrategy(),
retVal.getIndexModel(),
new ByteArrayId(
options.getNameOverride()));
}
return retVal;
}
public static String getIndexNamespace(
final String name ) {
return String.format(
"%s.%s",
INDEX_PROPERTY_NAMESPACE,
name);
}
public static enum PartitionStrategy {
NONE,
HASH,
ROUND_ROBIN;
}
abstract public static class BaseIndexBuilder<T extends IndexBuilder> implements
IndexBuilder
{
private final IndexPluginOptions options;
public BaseIndexBuilder() {
this(
new IndexPluginOptions());
}
private BaseIndexBuilder(
final IndexPluginOptions options ) {
this.options = options;
}
public T setNumPartitions(
final int numPartitions ) {
options.numPartitions = numPartitions;
return (T) this;
}
public T setPartitionStrategy(
final PartitionStrategy partitionStrategy ) {
options.partitionStrategy = partitionStrategy;
return (T) this;
}
public T setNameOverride(
final String nameOverride ) {
options.nameOverride = nameOverride;
return (T) this;
}
public PrimaryIndex createIndex(
final PrimaryIndex dimensionalityIndex ) {
return wrapIndexWithOptions(
dimensionalityIndex,
options);
}
}
}