/**
* Copyright 2013 Cloudera Inc.
*
* 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.
*/
package com.cloudera.cdk.data.hbase.impl;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.hbase.client.HTablePool;
import org.apache.hadoop.hbase.filter.CompareFilter;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import com.cloudera.cdk.data.PartitionKey;
import com.cloudera.cdk.data.hbase.filters.EntityFilter;
import com.cloudera.cdk.data.hbase.filters.RegexEntityFilter;
import com.cloudera.cdk.data.hbase.filters.SingleFieldEntityFilter;
/**
* An abstract class that EntityScanner implementations should extend to offer a
* builder interface. Implementations only need to implement the build method.
*
* @param <K>
* The underlying key record type
* @param <E>
* The entity type this canner scans
*/
public abstract class EntityScannerBuilder<E> {
private HTablePool tablePool;
private String tableName;
private PartitionKey startKey;
private PartitionKey stopKey;
private boolean startInclusive = true;
private boolean stopInclusive = false;
private int caching;
private EntityMapper<E> entityMapper;
private List<ScanModifier> scanModifiers = new ArrayList<ScanModifier>();
private boolean passAllFilters = true;
private List<Filter> filterList = new ArrayList<Filter>();
/**
* This is an abstract Builder object for the Entity Scanners, which will
* allow users to dynamically construct a scanner object using the Builder
* pattern. This is useful when the user doesn't have all the up front
* information to create a scanner. It's also easier to add more options later
* to the scanner, this will be the preferred method for users to create
* scanners.
*
* @param <K>
* The underlying key record type.
* @param <E>
* The entity type this scanner scans.
*/
public EntityScannerBuilder(HTablePool tablePool, String tableName,
EntityMapper<E> entityMapper) {
this.tablePool = tablePool;
this.tableName = tableName;
this.entityMapper = entityMapper;
}
/**
* Get The HBase Table Pool
*
* @return String
*/
HTablePool getTablePool() {
return tablePool;
}
/**
* Get The HBase Table Name
*
* @return String
*/
String getTableName() {
return tableName;
}
/**
* Get The Entity Mapper
*
* @return EntityMapper
*/
EntityMapper<E> getEntityMapper() {
return entityMapper;
}
/**
* Get The Start StorageKey
*
* @return StorageKey
*/
PartitionKey getStartKey() {
return startKey;
}
/**
* Set The Start StorageKey.
*
* @param startKey
* The start key for this scan
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> setStartKey(PartitionKey startKey) {
this.startKey = startKey;
return this;
}
/**
* Get The Start StorageKey
*
* @return StorageKey
*/
PartitionKey getStopKey() {
return stopKey;
}
/**
* Set The Stop StorageKey.
*
* @param stopKey
* The stop key for this scan
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> setStopKey(PartitionKey stopKey) {
this.stopKey = stopKey;
return this;
}
/**
* Returns true if the scan should include the row pointed to by the start
* key, or start right after it..
*
* @return startInclusive
*/
boolean getStartInclusive() {
return startInclusive;
}
/**
* Set the startInclusive parameter.
*
* @param startInclusive
* The startInclusive setting.
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> setStartInclusive(boolean startInclusive) {
this.startInclusive = startInclusive;
return this;
}
/**
* Returns true if the scan should include the row pointed to by the stop key,
* or stop just short of it.
*
* @return stopInclusive
*/
boolean getStopInclusive() {
return stopInclusive;
}
/**
* Set the startInclusive parameter.
*
* @param stopInclusive
* The stopInclusive setting.
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> setStopInclusive(boolean stopInclusive) {
this.stopInclusive = stopInclusive;
return this;
}
/**
* Get the scanner caching value
*
* @return the caching value
*/
int getCaching() {
return caching;
}
/**
* Set The Scanner Caching Level
*
* @param caching
* caching amount for scanner
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> setCaching(int caching) {
this.caching = caching;
return this;
}
/**
* Add an Equality Filter to the Scanner, Will Filter Results Not Equal to the
* Filter Value
*
* @param fieldName
* The name of the column you want to apply the filter on
* @param filterValue
* The value for comparison
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> addEqualFilter(String fieldName,
Object filterValue) {
SingleFieldEntityFilter singleFieldEntityFilter = new SingleFieldEntityFilter(
entityMapper.getEntitySchema(), entityMapper.getEntitySerDe(),
fieldName, filterValue, CompareFilter.CompareOp.EQUAL);
filterList.add(singleFieldEntityFilter.getFilter());
return this;
}
/**
* Add an Inequality Filter to the Scanner, Will Filter Results Not Equal to
* the Filter Value
*
* @param fieldName
* The name of the column you want to apply the filter on
* @param filterValue
* The value for comparison
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> addNotEqualFilter(String fieldName,
Object filterValue) {
SingleFieldEntityFilter singleFieldEntityFilter = new SingleFieldEntityFilter(
entityMapper.getEntitySchema(), entityMapper.getEntitySerDe(),
fieldName, filterValue, CompareFilter.CompareOp.NOT_EQUAL);
filterList.add(singleFieldEntityFilter.getFilter());
return this;
}
/**
* Add a Regex Equality Filter to the Scanner, Will Filter Results Not Equal
* to the Filter Value
*
* @param fieldName
* The name of the column you want to apply the filter on
* @param filterValue
* The regular expression to use for comparison
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> addRegexMatchFilter(String fieldName,
String regexString) {
RegexEntityFilter regexEntityFilter = new RegexEntityFilter(
entityMapper.getEntitySchema(), entityMapper.getEntitySerDe(),
fieldName, regexString);
filterList.add(regexEntityFilter.getFilter());
return this;
}
/**
* Add a Regex Inequality Filter to the Scanner, Will Filter Results Not Equal
* to the Filter Value
*
* @param fieldName
* The name of the column you want to apply the filter on
* @param filterValue
* The regular expression to use for comparison
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> addRegexNotMatchFilter(String fieldName,
String regexString) {
RegexEntityFilter regexEntityFilter = new RegexEntityFilter(
entityMapper.getEntitySchema(), entityMapper.getEntitySerDe(),
fieldName, regexString, false);
filterList.add(regexEntityFilter.getFilter());
return this;
}
/**
* Do not include rows which have no value for fieldName
*
* @param fieldName
* The field to check nullity
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> addNotNullFilter(String fieldName) {
RegexEntityFilter regexEntityFilter = new RegexEntityFilter(
entityMapper.getEntitySchema(), entityMapper.getEntitySerDe(),
fieldName, ".+");
filterList.add(regexEntityFilter.getFilter());
return this;
}
/**
* Only include rows which have an empty value for this field
*
* @param fieldName
* The field to check nullity
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> addIsNullFilter(String fieldName) {
RegexEntityFilter regexEntityFilter = new RegexEntityFilter(
entityMapper.getEntitySchema(), entityMapper.getEntitySerDe(),
fieldName, ".+", false);
filterList.add(regexEntityFilter.getFilter());
return this;
}
/**
* Only include rows which are missing this field, this was the only possible
* way to do it.
*
* @param fieldName
* The field which should be missing
* @return ScannerBuilder
*/
public EntityScannerBuilder<E> addIsMissingFilter(String fieldName) {
SingleFieldEntityFilter singleFieldEntityFilter = new SingleFieldEntityFilter(
entityMapper.getEntitySchema(), entityMapper.getEntitySerDe(),
fieldName, "++++NON_SHALL_PASS++++", CompareFilter.CompareOp.EQUAL);
SingleColumnValueFilter filter = (SingleColumnValueFilter) singleFieldEntityFilter
.getFilter();
filter.setFilterIfMissing(false);
filterList.add(filter);
return this;
}
/**
* Check If All Filters Must Pass
*
* @return boolean
*/
boolean getPassAllFilters() {
return passAllFilters;
}
public EntityScannerBuilder<E> setPassAllFilters(boolean passAllFilters) {
this.passAllFilters = passAllFilters;
return this;
}
/**
* Get The List Of Filters For This Scanner
*
* @return List
*/
List<Filter> getFilterList() {
return filterList;
}
/**
* Add HBase Filter To Scan Object
*
* @param filter
* EntityFilter object created by user
*/
public EntityScannerBuilder<E> addFilter(EntityFilter filter) {
filterList.add(filter.getFilter());
return this;
}
/**
* Get the ScanModifiers
*
* @return List of ScanModifiers
*/
List<ScanModifier> getScanModifiers() {
return scanModifiers;
}
/**
* Add the ScanModifier to the list of ScanModifiers.
*
* @param scanModifier
* The ScanModifier to add
*/
public EntityScannerBuilder<E> addScanModifier(ScanModifier scanModifier) {
scanModifiers.add(scanModifier);
return this;
}
/**
* Build and return a EntityScanner object using all of the information
* the user provided.
*
* @return ScannerBuilder
*/
public abstract EntityScanner<E> build();
}