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