001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.filter;
019
020import java.io.IOException;
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.Collections;
024import java.util.List;
025import java.util.Objects;
026import org.apache.hadoop.hbase.Cell;
027import org.apache.hadoop.hbase.exceptions.DeserializationException;
028import org.apache.yetus.audience.InterfaceAudience;
029
030import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
031
032import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
033import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos;
034
035/**
036 * Implementation of {@link Filter} that represents an ordered List of Filters which will be
037 * evaluated with a specified boolean operator {@link Operator#MUST_PASS_ALL} (<code>AND</code>) or
038 * {@link Operator#MUST_PASS_ONE} (<code>OR</code>). Since you can use Filter Lists as children of
039 * Filter Lists, you can create a hierarchy of filters to be evaluated. <br>
040 * {@link Operator#MUST_PASS_ALL} evaluates lazily: evaluation stops as soon as one filter does not
041 * include the Cell. <br>
042 * {@link Operator#MUST_PASS_ONE} evaluates non-lazily: all filters are always evaluated. <br>
043 * Defaults to {@link Operator#MUST_PASS_ALL}.
044 */
045@InterfaceAudience.Public
046final public class FilterList extends FilterBase {
047
048  /** set operator */
049  @InterfaceAudience.Public
050  public enum Operator {
051    /** !AND */
052    MUST_PASS_ALL,
053    /** !OR */
054    MUST_PASS_ONE
055  }
056
057  private Operator operator;
058  private FilterListBase filterListBase;
059
060  /**
061   * Constructor that takes a set of {@link Filter}s and an operator.
062   * @param operator Operator to process filter set with.
063   * @param filters  Set of row filters.
064   */
065  public FilterList(final Operator operator, final List<Filter> filters) {
066    if (operator == Operator.MUST_PASS_ALL) {
067      filterListBase = new FilterListWithAND(filters);
068    } else if (operator == Operator.MUST_PASS_ONE) {
069      filterListBase = new FilterListWithOR(filters);
070    } else {
071      throw new IllegalArgumentException("Invalid operator: " + operator);
072    }
073    this.operator = operator;
074  }
075
076  /**
077   * Constructor that takes a set of {@link Filter}s. The default operator MUST_PASS_ALL is assumed.
078   * All filters are cloned to internal list.
079   * @param filters list of filters
080   */
081  public FilterList(final List<Filter> filters) {
082    this(Operator.MUST_PASS_ALL, filters);
083  }
084
085  /**
086   * Constructor that takes a var arg number of {@link Filter}s. The default operator MUST_PASS_ALL
087   * is assumed.
088   */
089  public FilterList(final Filter... filters) {
090    this(Operator.MUST_PASS_ALL, Arrays.asList(filters));
091  }
092
093  /**
094   * Constructor that takes an operator.
095   * @param operator Operator to process filter set with.
096   */
097  public FilterList(final Operator operator) {
098    this(operator, new ArrayList<>());
099  }
100
101  /**
102   * Constructor that takes a var arg number of {@link Filter}s and an operator.
103   * @param operator Operator to process filter set with.
104   * @param filters  Filters to use
105   */
106  public FilterList(final Operator operator, final Filter... filters) {
107    this(operator, Arrays.asList(filters));
108  }
109
110  /**
111   * Get the operator.
112   */
113  public Operator getOperator() {
114    return operator;
115  }
116
117  /**
118   * Get the filters.
119   */
120  public List<Filter> getFilters() {
121    return filterListBase.getFilters();
122  }
123
124  public int size() {
125    return filterListBase.size();
126  }
127
128  public void addFilter(List<Filter> filters) {
129    filterListBase.addFilterLists(filters);
130  }
131
132  /**
133   * Add a filter.
134   * @param filter another filter
135   */
136  public void addFilter(Filter filter) {
137    addFilter(Collections.singletonList(filter));
138  }
139
140  @Override
141  public void reset() throws IOException {
142    filterListBase.reset();
143  }
144
145  @Override
146  public boolean filterRowKey(byte[] rowKey, int offset, int length) throws IOException {
147    return filterListBase.filterRowKey(rowKey, offset, length);
148  }
149
150  @Override
151  public boolean filterRowKey(Cell firstRowCell) throws IOException {
152    return filterListBase.filterRowKey(firstRowCell);
153  }
154
155  @Override
156  public boolean filterAllRemaining() throws IOException {
157    return filterListBase.filterAllRemaining();
158  }
159
160  @Override
161  public Cell transformCell(Cell c) throws IOException {
162    return filterListBase.transformCell(c);
163  }
164
165  @Override
166  @Deprecated
167  public ReturnCode filterKeyValue(final Cell c) throws IOException {
168    return filterCell(c);
169  }
170
171  @Override
172  public ReturnCode filterCell(final Cell c) throws IOException {
173    return filterListBase.filterCell(c);
174  }
175
176  /**
177   * Filters that never filter by modifying the returned List of Cells can inherit this
178   * implementation that does nothing. {@inheritDoc}
179   */
180  @Override
181  public void filterRowCells(List<Cell> cells) throws IOException {
182    filterListBase.filterRowCells(cells);
183  }
184
185  @Override
186  public boolean hasFilterRow() {
187    return filterListBase.hasFilterRow();
188  }
189
190  @Override
191  public boolean filterRow() throws IOException {
192    return filterListBase.filterRow();
193  }
194
195  /** Returns The filter serialized using pb */
196  @Override
197  public byte[] toByteArray() throws IOException {
198    FilterProtos.FilterList.Builder builder = FilterProtos.FilterList.newBuilder();
199    builder.setOperator(FilterProtos.FilterList.Operator.valueOf(operator.name()));
200    ArrayList<Filter> filters = filterListBase.getFilters();
201    for (int i = 0, n = filters.size(); i < n; i++) {
202      builder.addFilters(ProtobufUtil.toFilter(filters.get(i)));
203    }
204    return builder.build().toByteArray();
205  }
206
207  /**
208   * Parse a seralized representation of {@link FilterList}
209   * @param pbBytes A pb serialized {@link FilterList} instance
210   * @return An instance of {@link FilterList} made from <code>bytes</code>
211   * @throws DeserializationException if an error occurred
212   * @see #toByteArray
213   */
214  public static FilterList parseFrom(final byte[] pbBytes) throws DeserializationException {
215    FilterProtos.FilterList proto;
216    try {
217      proto = FilterProtos.FilterList.parseFrom(pbBytes);
218    } catch (InvalidProtocolBufferException e) {
219      throw new DeserializationException(e);
220    }
221
222    List<Filter> rowFilters = new ArrayList<>(proto.getFiltersCount());
223    try {
224      List<FilterProtos.Filter> filtersList = proto.getFiltersList();
225      for (int i = 0, n = filtersList.size(); i < n; i++) {
226        rowFilters.add(ProtobufUtil.toFilter(filtersList.get(i)));
227      }
228    } catch (IOException ioe) {
229      throw new DeserializationException(ioe);
230    }
231    return new FilterList(Operator.valueOf(proto.getOperator().name()), rowFilters);
232  }
233
234  /**
235   * Returns true if and only if the fields of the filter that are serialized are equal to the
236   * corresponding fields in other. Used for testing.
237   */
238  @Override
239  boolean areSerializedFieldsEqual(Filter other) {
240    if (other == this) {
241      return true;
242    }
243    if (!(other instanceof FilterList)) {
244      return false;
245    }
246    FilterList o = (FilterList) other;
247    return this.getOperator().equals(o.getOperator())
248      && ((this.getFilters() == o.getFilters()) || this.getFilters().equals(o.getFilters()));
249  }
250
251  @Override
252  public Cell getNextCellHint(Cell currentCell) throws IOException {
253    return this.filterListBase.getNextCellHint(currentCell);
254  }
255
256  @Override
257  public boolean isFamilyEssential(byte[] name) throws IOException {
258    return this.filterListBase.isFamilyEssential(name);
259  }
260
261  @Override
262  public void setReversed(boolean reversed) {
263    this.reversed = reversed;
264    this.filterListBase.setReversed(reversed);
265  }
266
267  @Override
268  public boolean isReversed() {
269    assert this.reversed == this.filterListBase.isReversed();
270    return this.reversed;
271  }
272
273  @Override
274  public String toString() {
275    return this.filterListBase.toString();
276  }
277
278  @Override
279  public boolean equals(Object obj) {
280    return obj instanceof Filter && areSerializedFieldsEqual((Filter) obj);
281  }
282
283  @Override
284  public int hashCode() {
285    return Objects.hash(getOperator(), getFilters());
286  }
287}