/*==========================================================================*\ | $Id: ModifierFilter.java,v 1.1 2011/06/09 15:31:24 stedwar2 Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2011 Virginia Tech | | This file is part of the Student-Library. | | The Student-Library is free software; you can redistribute it and/or | modify it under the terms of the GNU Lesser General Public License as | published by the Free Software Foundation; either version 3 of the | License, or (at your option) any later version. | | The Student-Library is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU Lesser General Public License for more details. | | You should have received a copy of the GNU Lesser General Public License | along with the Student-Library; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package student.testingsupport.reflection; import java.lang.reflect.Modifier; //------------------------------------------------------------------------- /** * TODO: document. * * @param <ConcreteFilterType> A parameter indicating the concrete subclass * of this class, for use in providing more specialized return types on * some methods. * @param <FilteredObjectType> A parameter indicating the kind of object * this filter accepts. * * @author Stephen Edwards * @author Last changed by $Author: stedwar2 $ * @version $Revision: 1.1 $, $Date: 2011/06/09 15:31:24 $ */ public abstract class ModifierFilter<ConcreteFilterType, FilteredObjectType> extends Filter<ConcreteFilterType, FilteredObjectType> { //~ Fields ................................................................ private Integer requiredModifiers; private Integer mustNotHaveModifiers; //~ Constructor ........................................................... // ---------------------------------------------------------- /** * Create a new VisibilityFilter object. * @param previous The previous filter in the chain of filters. * @param descriptionOfConstraint A description of the constraint imposed * by this filter (just one step in the chain). */ protected ModifierFilter( ModifierFilter<ConcreteFilterType, FilteredObjectType> previous, String descriptionOfConstraint) { super(previous, descriptionOfConstraint); } //~ Public Methods ........................................................ // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that have "public" * visibility. * @return The restricted filter. */ public ConcreteFilterType declaredPublic() { return withModifiers(Modifier.PUBLIC, "declared public"); } // ---------------------------------------------------------- /** * Determine whether this object is declared "public". * @return True if this is declared public. */ public boolean isPublic() { return hasModifiers(Modifier.PUBLIC); } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that have "protected" * visibility. * @return The restricted filter. */ public ConcreteFilterType declaredProtected() { return withModifiers(Modifier.PROTECTED, "declared protected"); } // ---------------------------------------------------------- /** * Determine whether this object is declared "protected". * @return True if this is declared protected. */ public boolean isProtected() { return hasModifiers(Modifier.PROTECTED); } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that have "private" * visibility. * @return The restricted filter. */ public ConcreteFilterType declaredPrivate() { return withModifiers(Modifier.PRIVATE, "declared private"); } // ---------------------------------------------------------- /** * Determine whether this object is declared "private". * @return True if this is declared private. */ public boolean isPrivate() { return hasModifiers(Modifier.PRIVATE); } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that have "default" * visibility (package-level visibility). * @return The restricted filter. */ public ConcreteFilterType declaredPackageVisible() { return withoutModifiers( Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE, "declared package-visible"); } // ---------------------------------------------------------- /** * Determine whether this object is declared to have "default" visibility * (package-level visibility). * @return True if this is declared package-level. */ public boolean isPackageVisible() { return doesNotHaveModifiers( Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE); } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that are "static". * @return The restricted filter. */ public ConcreteFilterType declaredStatic() { return withModifiers(Modifier.STATIC, "declared static"); } // ---------------------------------------------------------- /** * Determine whether this object is declared "static". * @return True if this is declared static. */ public boolean isStatic() { return hasModifiers(Modifier.STATIC); } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that are "final". * @return The restricted filter. */ public ConcreteFilterType declaredFinal() { return withModifiers(Modifier.FINAL, "declared final"); } // ---------------------------------------------------------- /** * Determine whether this object is declared "final". * @return True if this is declared final. */ public boolean isFinal() { return hasModifiers(Modifier.FINAL); } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that have all of the * given modifiers. The parameter is an integer bit mask in the * same style of {@link Modifier}. * @param modifiers The modifiers required by this filter. * @return The restricted filter. */ public ConcreteFilterType withModifiers(int modifiers) { return withModifiers(modifiers, "with modifiers <" + modifiers + ">"); } // ---------------------------------------------------------- /** * Determine whether the objects matching this filter have all of the * given modifiers. * @param modifiers The modifiers to check. * @return True if all given modifiers are present. */ public boolean hasModifiers(final int modifiers) { if (exists()) { return quantify.evaluate(new Predicate<FilteredObjectType>() { public boolean isSatisfiedBy(FilteredObjectType object) { return (modifiersFor(object) & modifiers) == modifiers; } }); } else { int modifiersPresent = requiredModifiers() & modifiers; int remaining = modifiers - modifiersPresent; if (remaining == 0) { return true; } else if (previousFilter() != null && previousFilter() instanceof ModifierFilter) { @SuppressWarnings("rawtypes") ModifierFilter filter = (ModifierFilter)previousFilter(); return filter.hasModifiers(remaining); } else { return false; } } } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that do not have the * any of the given modifiers. The parameter is an integer bit mask in * the same style of {@link Modifier}. * @param modifiers The modifiers denied by this filter. * @return The restricted filter. */ public ConcreteFilterType withoutModifiers(int modifiers) { return withoutModifiers( modifiers, "without modifiers <" + modifiers + ">"); } // ---------------------------------------------------------- /** * Determine whether the objects matching this filter omit all of the * given modifiers. * @param modifiers The modifiers to check. * @return True if all given modifiers are absent. */ public boolean doesNotHaveModifiers(final int modifiers) { if (exists()) { return quantify.evaluate(new Predicate<FilteredObjectType>() { public boolean isSatisfiedBy(FilteredObjectType object) { return (modifiersFor(object) & modifiers) == 0; } }); } else { int modifiersAbsent = mustNotHaveModifiers() & modifiers; int remaining = modifiers - modifiersAbsent; if (remaining == 0) { return true; } else if (previousFilter() != null && previousFilter() instanceof ModifierFilter) { @SuppressWarnings("rawtypes") ModifierFilter filter = (ModifierFilter)previousFilter(); return filter.doesNotHaveModifiers(remaining); } else { return false; } } } //~ Protected Methods ..................................................... // ---------------------------------------------------------- /** * Extract the modifiers from the specified object. * @param object The object to retrieve modifiers from * @return A single value representing all the modifiers on the object. */ protected abstract int modifiersFor(FilteredObjectType object); // ---------------------------------------------------------- /** * TODO: document. * @param object TODO: describe * @return TODO: describe */ protected boolean thisFilterAccepts(FilteredObjectType object) { int required = requiredModifiers(); int mustNotHave = mustNotHaveModifiers(); return ((modifiersFor(object) & required) == required) && ((modifiersFor(object) & mustNotHave) == 0); } // ---------------------------------------------------------- /** * TODO: document. * @return TODO: describe */ protected int requiredModifiers() { return (requiredModifiers == null) ? defaultRequiredModifiers() : requiredModifiers; } // ---------------------------------------------------------- /** * TODO: document. * @return TODO: describe */ protected int defaultRequiredModifiers() { if (previousFilter() != null && previousFilter() instanceof ModifierFilter) { @SuppressWarnings("rawtypes") ModifierFilter filter = (ModifierFilter)previousFilter(); return filter.defaultRequiredModifiers(); } return Modifier.PUBLIC; } // ---------------------------------------------------------- /** * TODO: document. * @return TODO: describe */ protected int mustNotHaveModifiers() { return (mustNotHaveModifiers == null) ? defaultMustNotHaveModifiers() : mustNotHaveModifiers; } // ---------------------------------------------------------- /** * TODO: document. * @return TODO: describe */ protected int defaultMustNotHaveModifiers() { if (previousFilter() != null && previousFilter() instanceof ModifierFilter) { @SuppressWarnings("rawtypes") ModifierFilter filter = (ModifierFilter)previousFilter(); return filter.defaultMustNotHaveModifiers(); } return Modifier.STATIC; } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that have all of the * given modifiers. The parameter is an integer bit mask in the * same style of {@link Modifier}. * @param modifiers The modifiers required by this filter. * @param description The description of this constraint. * @return The restricted filter. */ @SuppressWarnings("unchecked") protected ConcreteFilterType withModifiers( int modifiers, String description) { ConcreteFilterType result = createFreshFilter((ConcreteFilterType)this, description); ModifierFilter<ConcreteFilterType, FilteredObjectType> filter = (ModifierFilter<ConcreteFilterType, FilteredObjectType>)result; filter.requiredModifiers = modifiers; return result; } // ---------------------------------------------------------- /** * Restrict this filter to only admit declarations that do not have the * any of the given modifiers. The parameter is an integer bit mask in * the same style of {@link Modifier}. * @param modifiers The modifiers denied by this filter. * @param description The description of this constraint. * @return The restricted filter. */ @SuppressWarnings("unchecked") protected ConcreteFilterType withoutModifiers( int modifiers, String description) { ConcreteFilterType result = createFreshFilter((ConcreteFilterType)this, description); ModifierFilter<ConcreteFilterType, FilteredObjectType> filter = (ModifierFilter<ConcreteFilterType, FilteredObjectType>)result; filter.mustNotHaveModifiers = modifiers; return result; } }