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;
026
027import org.apache.hadoop.hbase.Cell;
028import org.apache.yetus.audience.InterfaceAudience;
029import org.apache.hadoop.hbase.exceptions.DeserializationException;
030
031import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
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   * @param filters
089   */
090  public FilterList(final Filter... filters) {
091    this(Operator.MUST_PASS_ALL, Arrays.asList(filters));
092  }
093
094  /**
095   * Constructor that takes an operator.
096   * @param operator Operator to process filter set with.
097   */
098  public FilterList(final Operator operator) {
099    this(operator, new ArrayList<>());
100  }
101
102  /**
103   * Constructor that takes a var arg number of {@link Filter}s and an operator.
104   * @param operator Operator to process filter set with.
105   * @param filters Filters to use
106   */
107  public FilterList(final Operator operator, final Filter... filters) {
108    this(operator, Arrays.asList(filters));
109  }
110
111  /**
112   * Get the operator.
113   * @return operator
114   */
115  public Operator getOperator() {
116    return operator;
117  }
118
119  /**
120   * Get the filters.
121   * @return filters
122   */
123  public List<Filter> getFilters() {
124    return filterListBase.getFilters();
125  }
126
127  public int size() {
128    return filterListBase.size();
129  }
130
131  public void addFilter(List<Filter> filters) {
132    filterListBase.addFilterLists(filters);
133  }
134
135  /**
136   * Add a filter.
137   * @param filter another filter
138   */
139  public void addFilter(Filter filter) {
140    addFilter(Collections.singletonList(filter));
141  }
142
143  @Override
144  public void reset() throws IOException {
145    filterListBase.reset();
146  }
147
148  @Override
149  public boolean filterRowKey(byte[] rowKey, int offset, int length) throws IOException {
150    return filterListBase.filterRowKey(rowKey, offset, length);
151  }
152
153  @Override
154  public boolean filterRowKey(Cell firstRowCell) throws IOException {
155    return filterListBase.filterRowKey(firstRowCell);
156  }
157
158  @Override
159  public boolean filterAllRemaining() throws IOException {
160    return filterListBase.filterAllRemaining();
161  }
162
163  @Override
164  public Cell transformCell(Cell c) throws IOException {
165    return filterListBase.transformCell(c);
166  }
167
168  @Override
169  @Deprecated
170  public ReturnCode filterKeyValue(final Cell c) throws IOException {
171    return filterCell(c);
172  }
173
174  @Override
175  public ReturnCode filterCell(final Cell c) throws IOException {
176    return filterListBase.filterCell(c);
177  }
178
179  /**
180   * Filters that never filter by modifying the returned List of Cells can inherit this
181   * implementation that does nothing. {@inheritDoc}
182   */
183  @Override
184  public void filterRowCells(List<Cell> cells) throws IOException {
185    filterListBase.filterRowCells(cells);
186  }
187
188  @Override
189  public boolean hasFilterRow() {
190    return filterListBase.hasFilterRow();
191  }
192
193  @Override
194  public boolean filterRow() throws IOException {
195    return filterListBase.filterRow();
196  }
197
198  /**
199   * @return The filter serialized using pb
200   */
201  @Override
202  public byte[] toByteArray() throws IOException {
203    FilterProtos.FilterList.Builder builder = FilterProtos.FilterList.newBuilder();
204    builder.setOperator(FilterProtos.FilterList.Operator.valueOf(operator.name()));
205    ArrayList<Filter> filters = filterListBase.getFilters();
206    for (int i = 0, n = filters.size(); i < n; i++) {
207      builder.addFilters(ProtobufUtil.toFilter(filters.get(i)));
208    }
209    return builder.build().toByteArray();
210  }
211
212  /**
213   * @param pbBytes A pb serialized {@link FilterList} instance
214   * @return An instance of {@link FilterList} made from <code>bytes</code>
215   * @throws DeserializationException
216   * @see #toByteArray
217   */
218  public static FilterList parseFrom(final byte[] pbBytes) throws DeserializationException {
219    FilterProtos.FilterList proto;
220    try {
221      proto = FilterProtos.FilterList.parseFrom(pbBytes);
222    } catch (InvalidProtocolBufferException e) {
223      throw new DeserializationException(e);
224    }
225
226    List<Filter> rowFilters = new ArrayList<>(proto.getFiltersCount());
227    try {
228      List<FilterProtos.Filter> filtersList = proto.getFiltersList();
229      for (int i = 0, n = filtersList.size(); i < n; i++) {
230        rowFilters.add(ProtobufUtil.toFilter(filtersList.get(i)));
231      }
232    } catch (IOException ioe) {
233      throw new DeserializationException(ioe);
234    }
235    return new FilterList(Operator.valueOf(proto.getOperator().name()), rowFilters);
236  }
237
238  /**
239   * @param other
240   * @return true if and only if the fields of the filter that are serialized are equal to the
241   *         corresponding fields in other. Used for testing.
242   */
243  @Override
244  boolean areSerializedFieldsEqual(Filter other) {
245    if (other == this) return true;
246    if (!(other instanceof FilterList)) return false;
247
248    FilterList o = (FilterList) other;
249    return this.getOperator().equals(o.getOperator())
250        && ((this.getFilters() == o.getFilters()) || this.getFilters().equals(o.getFilters()));
251  }
252
253  @Override
254  public Cell getNextCellHint(Cell currentCell) throws IOException {
255    return this.filterListBase.getNextCellHint(currentCell);
256  }
257
258  @Override
259  public boolean isFamilyEssential(byte[] name) throws IOException {
260    return this.filterListBase.isFamilyEssential(name);
261  }
262
263  @Override
264  public void setReversed(boolean reversed) {
265    this.reversed = reversed;
266    this.filterListBase.setReversed(reversed);
267  }
268
269  @Override
270  public boolean isReversed() {
271    assert this.reversed == this.filterListBase.isReversed();
272    return this.reversed;
273  }
274
275  @Override
276  public String toString() {
277    return this.filterListBase.toString();
278  }
279}