package MusicLandscape.util.matcher;
import MusicLandscape.entities.Track;
import MusicLandscape.util.MyMatcher;package MusicLandscape.util.matcher;
import MusicLandscape.entities.Track;
import MusicLandscape.util.MyMatcher;Matchers are more complicated than Comparators. The matches()
method itself is quite simple, but the setPattern() code to parse the
matcher configuration from a string is where the complexity comes in.
/**
* Encapsulates the concept of matching a track based on its duration.
* <p>
* This class is used to test whether given a given track's duration lies in a certain range, the range being the
* pattern of this matcher.The pattern is a simple string consisting of the (white-space separated) lower and upper
* bounds (inclusive) of the range of duration s (in seconds) accepted by this matcher.
* <p>
* More precisely, a valid pattern is a String that can be interpreted as either a single integer number
* (leading and trailing whitespace are ignored, if present) which then represents the lower bound
* or two integer numbers, separated by (any number of) whitespace, which then represent lower and upper bound.
* <p>
* The bounds are understood to be inclusive.
*
* @author Jonas Altrock (ew20b126@technikum-wien.at)
* @version 1
* @since ExerciseSheet05
*/
public class DurationMatcher extends MyMatcher<Track> {
/**
* the lower bound of the accepted range.
*/
private int lower;
/**
* the upper bound of the accepted range.
*/
private int upper;
/**
* Creates a default duration matcher.<br>
* By default, a matcher matches any duration, including unknown duration.
*/
public DurationMatcher() {
super("");
}
/**
* Creates a duration matcher with a specified pattern.
*
* @param pat the pattern of this matcher
*/
public DurationMatcher(String pat) {
super(pat);
}
/**
* A track matches if its duration is in the range accepted by this matcher.
*
* @param track the object to match
* @return whether t matches the pattern of this matcher.
*/
@Override
public boolean matches(Track track) {
return track.getDuration() >= lower && track.getDuration() <= upper;
}
/**
* Sets the pattern of this matcher.
* <p>
* Interprets the argument as described in the class documentation. First sets the lower, then the upper bound.
* The bounds specified are set if and only if at the time of setting they are actually lower (for the lower bound)
* or higher (for the upper bound) than the other or at least equal to the other.
*
* @param pat the pattern to set
*/
@Override
public void setPattern(String pat) {First I split the incoming string into two parts.
\s is regular expression for any whitespace, the backspace \
needs to be doubled because Java strings can also contain escape
codes that start with the backslash, like \n.+ is for one or more occurrences, so “at least one whitespace”. String[] parts = pat.trim().split("\\s+");Here we have our default values for the lower and upper bounds.
lower = 0;
upper = Integer.MAX_VALUE;
if (parts.length < 1 || parts[0].isEmpty()) {
return;
}
try {Using Integer.max is a short hand for checking if the
parsed integer is smaller than 0 (i.e. negative).
lower = Integer.max(Integer.parseInt(parts[0]), 0);
} catch (NumberFormatException ignored) {}
if (parts.length < 2) {
return;
}
try {Same in the “other direction”: using Integer.min makes sure
the value is below the maximum upper bound. This is a little
pointless, because upper == Integer.MAX_VALUE , and parseInt
will never return a value larger than that.
int upperBound = Integer.min(Integer.parseInt(parts[1]), upper);
if (upperBound >= lower) {
upper = upperBound;
}
} catch (NumberFormatException ignored) {}
}
/**
* the valid pattern is <kbd>LOWER UPPER</kbd> separated by whitespace.
*
* @return the pattern
*/
@Override
public String getPattern() {
return lower + " " + upper;
}
/**
* the string representation is duration in range (RANGE)<br>
* with range as described in getPattern
*
* @return a string representation of the object.
*/
@Override
public String toString() {
return "duration in range (" + lower + " " + upper + ")";
}
}