/* * Copyright 2012 NGDATA nv * * 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 org.lilyproject.repository.impl.hbase; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.SortedMap; import com.google.common.base.Predicate; import com.google.common.collect.Maps; import org.apache.hadoop.hbase.filter.FilterBase; import org.lilyproject.bytes.impl.DataInputImpl; import org.lilyproject.repository.api.RecordId; import org.lilyproject.repository.impl.id.IdGeneratorImpl; import org.lilyproject.util.ArgumentValidator; /** * Actual implementation of an HBase filter to filter out variant lily records. This returns all records which have * exactly the given variant properties (i.e. not the records which have these variant properties and some additional * ones). If the value of the variant property is specified, it has to match exactly. If the value is * <code>null</code>, any value will match. */ public class LilyRecordVariantFilter extends FilterBase { private Map<String, String> variantProperties; private final IdGeneratorImpl idGenerator = new IdGeneratorImpl(); /** * @param variantProperties the variant properties that the records should have */ public LilyRecordVariantFilter(final Map<String, String> variantProperties) { ArgumentValidator.notNull(variantProperties, "variantProperties"); this.variantProperties = variantProperties; } public LilyRecordVariantFilter() { // for hbase readFields } public Map<String, String> getVariantProperties() { return variantProperties; } public boolean filterRowKey(byte[] buffer, int offset, int length) { // note: return value true means it is NOT a result of the scanner, false otherwise if (buffer == null) { return true; } final RecordId recordId = idGenerator.fromBytes(new DataInputImpl(buffer, offset, length)); final SortedMap<String, String> recordVariantProperties = recordId.getVariantProperties(); // check if the record has all expected variant properties if (containsAllExpectedDimensions(recordVariantProperties) && hasSameValueForValuedDimensions(recordVariantProperties)) { // check if the record doesn't have other variant properties return variantProperties.size() != recordVariantProperties.size(); } else { return true; } } private boolean containsAllExpectedDimensions(Map<String, String> recordVariantProperties) { return recordVariantProperties.keySet().containsAll(this.variantProperties.keySet()); } private boolean hasSameValueForValuedDimensions(Map<String, String> variantProperties) { return variantProperties.entrySet().containsAll(getValuedDimensions().entrySet()); } private Map<String, String> getValuedDimensions() { return Maps.filterValues(variantProperties, new Predicate<String>() { @Override public boolean apply(String input) { return input != null; } }); } public void write(DataOutput out) throws IOException { out.writeInt(variantProperties.size()); for (Map.Entry<String, String> variantProperty : variantProperties.entrySet()) { out.writeUTF(variantProperty.getKey()); out.writeUTF(variantProperty.getValue() != null ? variantProperty.getValue() : "\u0000"); } } public void readFields(DataInput in) throws IOException { final int size = in.readInt(); variantProperties = new HashMap<String, String>(size); for (int i = 0; i < size; i++) { final String key = in.readUTF(); final String value = in.readUTF(); variantProperties.put(key, value.equals("\u0000") ? null : value); } } }