edu.byu.hbll.callnumber.CallNumberParser Maven / Gradle / Ivy
package edu.byu.hbll.callnumber;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** Provides the main entry point for parsing call number strings into CallNumber entities. */
public final class CallNumberParser {
/**
* A prebuilt CallNumberParser that will attempt to parse call numbers in the following order of
* precedence:
*
*
* - LCCallNumber
*
- DeweyCallNumber
*
- SymphonyDefaultCallNumber
*
- UnclassifiedCallNumber
*
*
* Because of the inclusion of the UnclassifiedCallNumber class, this CallNumberParser is
* guaranteed to parse any string.
*
*
Future updates may add additional CallNumber implementations to the list of targets in the
* prebuilt parser, but no target types will be removed. Subsequent additions to the target list
* will always be inserted immediately before SymphonyDefaultCallNumber.
*/
public static final CallNumberParser SYMPHONY_NONSTRICT =
new CallNumberParser(
LCCallNumber.class,
DeweyCallNumber.class,
SymphonyDefaultCallNumber.class,
UnclassifiedCallNumber.class);
/**
* A prebuilt CallNumberParser that will attempt to parse call numbers in the following order of
* precedence:
*
*
* - LCCallNumber
*
- DeweyCallNumber
*
- SymphonyDefaultCallNumber
*
*
* Because UnclassifiedCallNumber is NOT included in the targets for this parser, parsing a
* string that does not match any of the provided target types will result in an
* IllegalArgumentException.
*
*
Future updates may add additional CallNumber implementations to the list of targets in the
* prebuilt parser, but no target types will be removed. Subsequent additions to the target list
* will always be inserted immediately before SymphonyDefaultCallNumber.
*/
public static final CallNumberParser SYMPHONY_STRICT =
new CallNumberParser(
LCCallNumber.class, DeweyCallNumber.class, SymphonyDefaultCallNumber.class);
/**
* The list of call number constructors, in order of precendence, that should be used as parsing
* targets.
*/
private final List> implementationConstructors;
/**
* Constructs a new instance using the provided array of CallNumber implementation classes to
* define the possible parsing targets (as well as their order of precedence).
*
* @param targetTypes the classes to use as parsing targets
* @throws IllegalArgumentException if any of the provided targetTypes classes fails to provide a
* single argument (String) constructor per the contract of the CallNumber interface.
*/
@SafeVarargs
public CallNumberParser(Class extends CallNumber>... targetTypes)
throws IllegalArgumentException {
if (targetTypes.length < 1) {
throw new NullPointerException("at least one target type must be defined");
}
List> implementationConstructors = new ArrayList<>();
for (Class extends CallNumber> targetType : targetTypes) {
if (targetType == null) {
throw new IllegalArgumentException("target types must be non-null");
}
try {
implementationConstructors.add(targetType.getConstructor(String.class));
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(
targetType.getName()
+ " must define the following constructor: "
+ targetType.getSimpleName()
+ "(String str)");
}
}
this.implementationConstructors = Collections.unmodifiableList(implementationConstructors);
}
/**
* Parses the provided string into the first matching CallNumber implementation defined in this
* CallNumberParser.
*
* @param str the string to parse.
* @return the resulting call number
* @throws IllegalArgumentException if the provided string did not match the construction rules
* for any of the defined CallNumber implementations.
*/
public CallNumber parse(String str) throws IllegalArgumentException {
// Iterate through each provided implementation in order and try to match
for (Constructor extends CallNumber> implementationConstructor : implementationConstructors) {
try {
return implementationConstructor.newInstance(str);
} catch (Exception e) {
// The provided string does not match this implementation. Move on to the next
// implementation.
}
}
// If we have not yet returned then the parsing has failed
throw new IllegalArgumentException("Provided string is unparseable by any implementation");
}
}