001: /*
002: * @(#)DeclarationFilter.java 1.2 04/07/19
003: *
004: * Copyright (c) 2004, Sun Microsystems, Inc.
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions are met:
009: *
010: * * Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: * * Neither the name of the Sun Microsystems, Inc. nor the names of
016: * its contributors may be used to endorse or promote products derived from
017: * this software without specific prior written permission.
018: *
019: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
020: * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
021: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
022: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
023: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
024: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
025: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
026: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
027: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
028: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030: */
031:
032: package com.sun.mirror.util;
033:
034: import java.util.ArrayList;
035: import java.util.Collection;
036:
037: import com.sun.mirror.declaration.Declaration;
038: import com.sun.mirror.declaration.Modifier;
039:
040: import static com.sun.mirror.declaration.Modifier.*;
041:
042: /**
043: * A filter for selecting just the items of interest
044: * from a collection of declarations.
045: * The filter is said to <i>select</i> or to <i>match</i> those declarations.
046: * Filters can be created in several ways:
047: * by the static methods described below,
048: * by negating or composing existing filters,
049: * or by subclasses that implement arbitrary matching rules.
050: *
051: * <p> A subclass can create an arbitrary filter simply by implementing
052: * the {@link #matches(Declaration)} method.
053: *
054: * <p> Examples.
055: * <p> Selecting the <tt>public</tt> declarations from a collection:
056: * <blockquote><pre>
057: * result = FILTER_PUBLIC.filter(decls); </pre></blockquote>
058: * Selecting class declarations (including enums):
059: * <blockquote><pre>
060: * classFilter = DeclarationFilter.getFilter(ClassDeclaration.class);
061: * result = classFilter.filter(decls); </pre></blockquote>
062: * Selecting class declarations but excluding enums:
063: * <blockquote><pre>
064: * enumFilter = DeclarationFilter.getFilter(EnumDeclaration.class);
065: * compoundFilter = classFilter.and(enumFilter.not());
066: * result = compoundFilter.filter(decls); </pre></blockquote>
067: * Selecting declarations named "Bob":
068: * <blockquote><pre>
069: * nameFilter = new DeclarationFilter() {
070: * public boolean matches(Declaration d) {
071: * return d.getSimpleName().equals("Bob");
072: * }
073: * };
074: * result = nameFilter.filter(decls); </pre></blockquote>
075: *
076: * @author Joseph D. Darcy
077: * @author Scott Seligman
078: * @version 1.2 04/07/19
079: * @since 1.5
080: */
081:
082: public class DeclarationFilter {
083:
084: // Predefined filters for convenience.
085:
086: /**
087: * A filter that selects only <tt>public</tt> declarations.
088: */
089: public static final DeclarationFilter FILTER_PUBLIC = new AccessFilter(
090: PUBLIC);
091:
092: /**
093: * A filter that selects only <tt>protected</tt> declarations.
094: */
095: public static final DeclarationFilter FILTER_PROTECTED = new AccessFilter(
096: PROTECTED);
097:
098: /**
099: * A filter that selects only <tt>public</tt> or <tt>protected</tt>
100: * declarations.
101: */
102: public static final DeclarationFilter FILTER_PUBLIC_OR_PROTECTED = new AccessFilter(
103: PUBLIC, PROTECTED);
104:
105: /**
106: * A filter that selects only package-private (<i>default</i>)
107: * declarations.
108: */
109: public static final DeclarationFilter FILTER_PACKAGE = new AccessFilter();
110:
111: /**
112: * A filter that selects only <tt>private</tt> declarations.
113: */
114: public static final DeclarationFilter FILTER_PRIVATE = new AccessFilter(
115: PRIVATE);
116:
117: /**
118: * Constructs an identity filter: one that selects all declarations.
119: */
120: public DeclarationFilter() {
121: }
122:
123: // Methods to create a filter.
124:
125: /**
126: * Returns a filter that selects declarations containing all of a
127: * collection of modifiers.
128: *
129: * @param mods the modifiers to match (non-null)
130: * @return a filter that matches declarations containing <tt>mods</tt>
131: */
132: public static DeclarationFilter getFilter(
133: final Collection<Modifier> mods) {
134: return new DeclarationFilter() {
135: public boolean matches(Declaration d) {
136: return d.getModifiers().containsAll(mods);
137: }
138: };
139: }
140:
141: /**
142: * Returns a filter that selects declarations of a particular kind.
143: * For example, there may be a filter that selects only class
144: * declarations, or only fields.
145: * The filter will select declarations of the specified kind,
146: * and also any subtypes of that kind; for example, a field filter
147: * will also select enum constants.
148: *
149: * @param kind the kind of declarations to select
150: * @return a filter that selects declarations of a particular kind
151: */
152: public static DeclarationFilter getFilter(
153: final Class<? extends Declaration> kind) {
154: return new DeclarationFilter() {
155: public boolean matches(Declaration d) {
156: return kind.isInstance(d);
157: }
158: };
159: }
160:
161: /**
162: * Returns a filter that selects those declarations selected
163: * by both this filter and another.
164: *
165: * @param f filter to be composed with this one
166: * @return a filter that selects those declarations selected by
167: * both this filter and another
168: */
169: public DeclarationFilter and(DeclarationFilter f) {
170: final DeclarationFilter f1 = this ;
171: final DeclarationFilter f2 = f;
172: return new DeclarationFilter() {
173: public boolean matches(Declaration d) {
174: return f1.matches(d) && f2.matches(d);
175: }
176: };
177: }
178:
179: /**
180: * Returns a filter that selects those declarations selected
181: * by either this filter or another.
182: *
183: * @param f filter to be composed with this one
184: * @return a filter that selects those declarations selected by
185: * either this filter or another
186: */
187: public DeclarationFilter or(DeclarationFilter f) {
188: final DeclarationFilter f1 = this ;
189: final DeclarationFilter f2 = f;
190: return new DeclarationFilter() {
191: public boolean matches(Declaration d) {
192: return f1.matches(d) || f2.matches(d);
193: }
194: };
195: }
196:
197: /**
198: * Returns a filter that selects those declarations not selected
199: * by this filter.
200: *
201: * @return a filter that selects those declarations not selected
202: * by this filter
203: */
204: public DeclarationFilter not() {
205: return new DeclarationFilter() {
206: public boolean matches(Declaration d) {
207: return !DeclarationFilter.this .matches(d);
208: }
209: };
210: }
211:
212: // Methods to apply a filter.
213:
214: /**
215: * Tests whether this filter matches a given declaration.
216: * The default implementation always returns <tt>true</tt>;
217: * subclasses should override this.
218: *
219: * @param decl the declaration to match
220: * @return <tt>true</tt> if this filter matches the given declaration
221: */
222: public boolean matches(Declaration decl) {
223: return true;
224: }
225:
226: /**
227: * Returns the declarations matched by this filter.
228: * The result is a collection of the same type as the argument;
229: * the {@linkplain #filter(Collection, Class) two-parameter version}
230: * of <tt>filter</tt> offers control over the result type.
231: *
232: * @param <D> type of the declarations being filtered
233: * @param decls declarations being filtered
234: * @return the declarations matched by this filter
235: */
236: public <D extends Declaration> Collection<D> filter(
237: Collection<D> decls) {
238: ArrayList<D> res = new ArrayList<D>(decls.size());
239: for (D d : decls) {
240: if (matches(d)) {
241: res.add(d);
242: }
243: }
244: return res;
245: }
246:
247: /**
248: * Returns the declarations matched by this filter, with the result
249: * being restricted to declarations of a given kind.
250: * Similar to the simpler
251: * {@linkplain #filter(Collection) single-parameter version}
252: * of <tt>filter</tt>, but the result type is specified explicitly.
253: *
254: * @param <D> type of the declarations being returned
255: * @param decls declarations being filtered
256: * @param resType type of the declarations being returned --
257: * the reflective view of <tt>D</tt>
258: * @return the declarations matched by this filter, restricted to those
259: * of the specified type
260: */
261: public <D extends Declaration> Collection<D> filter(
262: Collection<? extends Declaration> decls, Class<D> resType) {
263: ArrayList<D> res = new ArrayList<D>(decls.size());
264: for (Declaration d : decls) {
265: if (resType.isInstance(d) && matches(d)) {
266: res.add(resType.cast(d));
267: }
268: }
269: return res;
270: }
271:
272: /*
273: * A filter based on access modifiers.
274: */
275: private static class AccessFilter extends DeclarationFilter {
276:
277: // The first access modifier to filter on, or null if we're looking
278: // for declarations with no access modifiers.
279: private Modifier mod1 = null;
280:
281: // The second access modifier to filter on, or null if none.
282: private Modifier mod2 = null;
283:
284: // Returns a filter that matches declarations with no access
285: // modifiers.
286: AccessFilter() {
287: }
288:
289: // Returns a filter that matches m.
290: AccessFilter(Modifier m) {
291: mod1 = m;
292: }
293:
294: // Returns a filter that matches either m1 or m2.
295: AccessFilter(Modifier m1, Modifier m2) {
296: mod1 = m1;
297: mod2 = m2;
298: }
299:
300: public boolean matches(Declaration d) {
301: Collection<Modifier> mods = d.getModifiers();
302: if (mod1 == null) { // looking for package private
303: return !(mods.contains(PUBLIC)
304: || mods.contains(PROTECTED) || mods
305: .contains(PRIVATE));
306: }
307: return mods.contains(mod1)
308: && (mod2 == null || mods.contains(mod2));
309: }
310: }
311: }
|