/*==========================================================================*\
| $Id: NameFilter.java,v 1.2 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.util.regex.Pattern;
//-------------------------------------------------------------------------
/**
* 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.2 $, $Date: 2011/06/09 15:31:24 $
*/
public abstract class NameFilter<ConcreteFilterType, FilteredObjectType>
extends AnnotationFilter<ConcreteFilterType, FilteredObjectType>
{
//~ Fields ................................................................
private String requiredName;
private Pattern matchPattern;
private Pattern containsPattern;
//~ Constructor ...........................................................
// ----------------------------------------------------------
/**
* Create a new NameFilter 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 NameFilter(
NameFilter<ConcreteFilterType, FilteredObjectType> previous,
String descriptionOfConstraint)
{
super(previous, descriptionOfConstraint);
requiredName = null;
}
//~ Public Methods ........................................................
// ----------------------------------------------------------
/**
* Restrict this filter to only admit declarations with the specified
* name.
* @param name The name required by the resulting filter.
* @return A new filter with the given restriction.
*/
@SuppressWarnings("unchecked")
public ConcreteFilterType withName(String name)
{
if (name == null)
{
ConcreteFilterType result = (ConcreteFilterType)this;
return result;
}
ConcreteFilterType result = createFreshFilter(
(ConcreteFilterType)this, "with name \"" + name + '"');
NameFilter<ConcreteFilterType, FilteredObjectType> filter =
(NameFilter<ConcreteFilterType, FilteredObjectType>)result;
filter.requiredName = name;
return result;
}
// ----------------------------------------------------------
/**
* Restrict this filter to only admit declarations with a
* name matching the specified pattern (regular expression).
* @param pattern The pattern required by the resulting filter
* @return A new filter with the given restriction.
*/
@SuppressWarnings("unchecked")
public ConcreteFilterType withNameMatching(Pattern pattern)
{
if (pattern == null)
{
ConcreteFilterType result = (ConcreteFilterType)this;
return result;
}
ConcreteFilterType result = createFreshFilter(
(ConcreteFilterType)this, "with name matching \"" + pattern + '"');
NameFilter<ConcreteFilterType, FilteredObjectType> filter =
(NameFilter<ConcreteFilterType, FilteredObjectType>)result;
filter.matchPattern = pattern;
return result;
}
// ----------------------------------------------------------
/**
* Restrict this filter to only admit declarations with a
* name matching the specified pattern, interpreted as a regular
* expression.
* @param pattern The pattern required by the resulting filter
* @return A new filter with the given restriction.
*/
public ConcreteFilterType withNameMatching(String pattern)
{
if (pattern == null)
{
@SuppressWarnings("unchecked")
ConcreteFilterType result = (ConcreteFilterType)this;
return result;
}
return withNameMatching(Pattern.compile(pattern));
}
// ----------------------------------------------------------
/**
* Restrict this filter to only admit declarations with a
* name containing the specified pattern (a regular expression).
* @param pattern The pattern required by the resulting filter
* @return A new filter with the given restriction.
*/
@SuppressWarnings("unchecked")
public ConcreteFilterType withNameContaining(Pattern pattern)
{
if (pattern == null)
{
ConcreteFilterType result = (ConcreteFilterType)this;
return result;
}
ConcreteFilterType result = createFreshFilter(
(ConcreteFilterType)this, "with name matching \"" + pattern + '"');
NameFilter<ConcreteFilterType, FilteredObjectType> filter =
(NameFilter<ConcreteFilterType, FilteredObjectType>)result;
filter.containsPattern = pattern;
return result;
}
// ----------------------------------------------------------
/**
* Restrict this filter to only admit declarations with a
* name containing the specified pattern, interpreted as a
* regular expression.
* @param pattern The pattern required by the resulting filter
* @return A new filter with the given restriction.
*/
public ConcreteFilterType withNameContaining(String pattern)
{
if (pattern == null)
{
@SuppressWarnings("unchecked")
ConcreteFilterType result = (ConcreteFilterType)this;
return result;
}
return withNameContaining(Pattern.compile(pattern));
}
// ----------------------------------------------------------
/**
* Retrieve the name of the object matching this filter.
* @return The object's name.
*/
public String getName()
{
if (exists())
{
return nameOf(uniqueMatch());
}
else if (requiredName != null)
{
return requiredName;
}
else if (previousFilter() != null
&& previousFilter() instanceof NameFilter)
{
NameFilter<ConcreteFilterType, FilteredObjectType> filter =
(NameFilter<ConcreteFilterType, FilteredObjectType>)
previousFilter();
return filter.getName();
}
else
{
return null;
}
}
//~ Protected Methods .....................................................
// ----------------------------------------------------------
/**
* A helper for diagnostic messages that should be used in place
* of {@link #getName()} when you want a printable (i.e., non-null)
* name.
* @return The name, if it exists, or the string "unknown" if
* the name is null.
*/
protected String getNameOrUnknown()
{
String name = getName();
return (name == null) ? "unknown" : name;
}
// ----------------------------------------------------------
/**
* Extract the name from the specified object.
* @param object The object to retrieve modifiers from
* @return The name of the object.
*/
protected abstract String nameOf(FilteredObjectType object);
// ----------------------------------------------------------
/**
* TODO: document.
* @param object TODO: describe
* @return TODO: describe
*/
protected boolean thisFilterAccepts(FilteredObjectType object)
{
boolean result = true;
String name = nameOf(object);
if (requiredName != null)
{
result = requiredName.equals(nameOf(object));
}
if (result && matchPattern != null)
{
result = matchPattern.matcher(name).matches();
}
if (result && containsPattern != null)
{
result = containsPattern.matcher(name).find();
}
return result && super.thisFilterAccepts(object);
}
}