001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.filter;
020
021import java.util.Locale;
022import org.apache.yetus.audience.InterfaceAudience;
023import org.apache.hadoop.hbase.exceptions.DeserializationException;
024import org.apache.hadoop.hbase.shaded.protobuf.generated.ComparatorProtos;
025import org.apache.hadoop.hbase.util.Bytes;
026
027import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
028
029
030/**
031 * This comparator is for use with SingleColumnValueFilter, for filtering based on
032 * the value of a given column. Use it to test if a given substring appears
033 * in a cell value in the column. The comparison is case insensitive.
034 * <p>
035 * Only EQUAL or NOT_EQUAL tests are valid with this comparator.
036 * <p>
037 * For example:
038 * <p>
039 * <pre>
040 * SingleColumnValueFilter scvf =
041 *   new SingleColumnValueFilter("col", CompareOp.EQUAL,
042 *     new SubstringComparator("substr"));
043 * </pre>
044 */
045@InterfaceAudience.Public
046@SuppressWarnings("ComparableType") // Should this move to Comparator usage?
047public class SubstringComparator extends ByteArrayComparable {
048
049  private String substr;
050
051  /**
052   * Constructor
053   * @param substr the substring
054   */
055  public SubstringComparator(String substr) {
056    super(Bytes.toBytes(substr.toLowerCase(Locale.ROOT)));
057    this.substr = substr.toLowerCase(Locale.ROOT);
058  }
059
060  @Override
061  public byte[] getValue() {
062    return Bytes.toBytes(substr);
063  }
064
065  @Override
066  public int compareTo(byte[] value, int offset, int length) {
067    return Bytes.toString(value, offset, length).toLowerCase(Locale.ROOT).contains(substr) ? 0
068        : 1;
069  }
070
071  /**
072   * @return The comparator serialized using pb
073   */
074  @Override
075  public byte [] toByteArray() {
076    ComparatorProtos.SubstringComparator.Builder builder =
077      ComparatorProtos.SubstringComparator.newBuilder();
078    builder.setSubstr(this.substr);
079    return builder.build().toByteArray();
080  }
081
082  /**
083   * @param pbBytes A pb serialized {@link SubstringComparator} instance
084   * @return An instance of {@link SubstringComparator} made from <code>bytes</code>
085   * @throws DeserializationException
086   * @see #toByteArray
087   */
088  public static SubstringComparator parseFrom(final byte [] pbBytes)
089  throws DeserializationException {
090    ComparatorProtos.SubstringComparator proto;
091    try {
092      proto = ComparatorProtos.SubstringComparator.parseFrom(pbBytes);
093    } catch (InvalidProtocolBufferException e) {
094      throw new DeserializationException(e);
095    }
096    return new SubstringComparator(proto.getSubstr());
097  }
098
099  /**
100   * @param other
101   * @return true if and only if the fields of the comparator that are serialized
102   * are equal to the corresponding fields in other.  Used for testing.
103   */
104  @Override
105  boolean areSerializedFieldsEqual(ByteArrayComparable other) {
106    if (other == this) return true;
107    if (!(other instanceof SubstringComparator)) return false;
108
109    SubstringComparator comparator = (SubstringComparator)other;
110    return super.areSerializedFieldsEqual(comparator)
111      && this.substr.equals(comparator.substr);
112  }
113
114}