/** * Copyright 2010 Google Inc. * * 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.waveprotocol.wave.model.id; import org.waveprotocol.wave.model.util.Preconditions; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * An immutable filter representing a (possibly infinite) subset of all possible * WaveletIds. * * A filter comprises a (possibly empty) set of ids to explicitly accept, plus a * (possibly empty) set of id prefixes to accept. * * Matches against WaveletIds must be exact, but when matching a prefix, only * the {@link WaveletId#getId() local id} part of the WaveletId is considered. * Thus a WaveletId is accepted by an IdFilter if it exactly equals one of the * specified WaveletIds, or if its local id part starts with one of the * specified prefixes. * * An IdFilter with prefix "" accepts everything. An IdFilter with no prefix * and no id accepts nothing. * * IdFilter is a value class. Use {@link #accepts(IdFilter, WaveletId)} to * determine if a filter accepts an id. * * @author anorth@google.com (Alex North) */ public final class IdFilter { /** Creates a filter accepting the specified nonempty list of ids. */ public static IdFilter ofIds(WaveletId firstId, WaveletId... otherIds) { List<WaveletId> waveletIds = new ArrayList<WaveletId>(1 + otherIds.length); waveletIds.add(firstId); waveletIds.addAll(Arrays.asList(otherIds)); return of(waveletIds, Collections.<String>emptyList()); } /** Creates a filter accepting the specified nonempty list of prefixes. */ public static IdFilter ofPrefixes(String firstPrefix, String... otherPrefixes) { List<String> prefixes = new ArrayList<String>(1 + otherPrefixes.length); prefixes.add(firstPrefix); prefixes.addAll(Arrays.asList(otherPrefixes)); return of(Collections.<WaveletId>emptyList(), prefixes); } /** * Constructs an IdFilter that accepts the specified ids and prefixes. * * @throws NullPointerException if ids or prefixes is null */ public static IdFilter of(Collection<WaveletId> ids, Collection<String> prefixes) { return new IdFilter(ids, prefixes); } /** * Checks whether a wavelet id is accepted by filter. */ public static boolean accepts(IdFilter filter, WaveletId id) { boolean match = filter.ids.contains(id); Iterator<String> itr = filter.prefixes.iterator(); while (itr.hasNext() && !match) { match = id.getId().startsWith(itr.next()); } return match; } private final Set<WaveletId> ids; private final Set<String> prefixes; /** * Constructs an IdFilter that accepts the specified ids and prefixes. */ private IdFilter(Collection<WaveletId> ids, Collection<String> prefixes) { Preconditions.checkNotNull(ids, "null ids"); Preconditions.checkNotNull(prefixes, "null prefixes"); this.ids = Collections.unmodifiableSet(new HashSet<WaveletId>(ids)); this.prefixes = Collections.unmodifiableSet(new HashSet<String>(prefixes)); } /** * Gets an unmodifiable view on the WaveletIds covered by this filter. */ public Set<WaveletId> getIds() { return ids; } /** * Gets an unmodifiable view on the id prefixes covered by this filter. */ public Set<String> getPrefixes() { return prefixes; } @Override public final boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof IdFilter) { IdFilter that = (IdFilter) obj; return this.ids.equals(that.ids) && this.prefixes.equals(that.prefixes); } return false; } @Override public final int hashCode() { return (17 + 31 * ids.hashCode()) * 31 + prefixes.hashCode(); } @Override public final String toString() { StringBuilder resultBuilder = new StringBuilder("IdFilter["); // Distinguish no prefixes from a single empty prefix in String representation if (!prefixes.isEmpty()) { resultBuilder.append("prefixes=").append(prefixes); } if (!ids.isEmpty()) { if (!prefixes.isEmpty()) { resultBuilder.append(", "); } resultBuilder.append("ids=").append(ids); } return resultBuilder.append("]").toString(); } }