import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
//import org.collectionspace.services.common.authority.AuthorityItemRelations;
/**
// Used to determine when the displayName changes as part of the update.
protected String oldDisplayNameOnUpdate = null;
private final static String LIST_SUFFIX = "List";
+ private final static String ZERO_OR_MORE_ANY_CHAR_REGEX = ".*";
public AuthorityItemDocumentModelHandler(String authorityItemCommonSchemaName) {
this.authorityItemCommonSchemaName = authorityItemCommonSchemaName;
}
}
+ /**
+ * Returns the items in a list of term display names whose names contain
+ * a partial term (as might be submitted in a search query, for instance).
+ * @param termDisplayNameList a list of term display names.
+ * @param partialTerm a partial term display name; that is, a portion
+ * of a display name that might be expected to match 0-n terms in the list.
+ * @return a list of term display names that matches the partial term.
+ * Matches are case-insensitive. As well, before matching is performed, any
+ * special-purpose characters that may appear in the partial term (such as
+ * wildcards and anchor characters) are filtered out from both compared terms.
+ */
protected List<String> getPartialTermDisplayNameMatches(List<String> termDisplayNameList, String partialTerm) {
- List<String> result = new ArrayList<String>();
-
- for (String termDisplayName : termDisplayNameList) {
- if (termDisplayName.toLowerCase().contains(partialTerm.toLowerCase()) == true) {
- result.add(termDisplayName);
- }
- }
-
+ List<String> result = new ArrayList<>();
+ String partialTermMatchExpression = filterAnchorAndWildcardChars(partialTerm).toLowerCase();
+ try {
+ for (String termDisplayName : termDisplayNameList) {
+ if (termDisplayName.toLowerCase()
+ .matches(partialTermMatchExpression) == true) {
+ result.add(termDisplayName);
+ }
+ }
+ } catch (PatternSyntaxException pse) {
+ logger.warn("Error in regex match pattern '%s' for term display names: %s",
+ partialTermMatchExpression, pse.getMessage());
+ }
return result;
}
+ /**
+ * Filters user-supplied anchor and wildcard characters in a string,
+ * replacing them with equivalent regular expressions.
+ * @param term a term in which to filter anchor and wildcard characters.
+ * @return the term with those characters filtered.
+ */
+ protected String filterAnchorAndWildcardChars(String term) {
+ if (Tools.isBlank(term)) {
+ return term;
+ }
+ if (term.length() < 3) {
+ return term;
+ }
+ if (logger.isTraceEnabled()) {
+ logger.trace(String.format("Term = %s", term));
+ }
+ Boolean anchorAtStart = false;
+ Boolean anchorAtEnd = false;
+ String filteredTerm;
+ StringBuilder filteredTermBuilder = new StringBuilder(term);
+ // Term contains no anchor or wildcard characters.
+ if ( (! term.contains(RepositoryJavaClientImpl.USER_SUPPLIED_ANCHOR_CHAR))
+ && (! term.contains(RepositoryJavaClientImpl.USER_SUPPLIED_WILDCARD)) ) {
+ filteredTerm = term;
+ } else {
+ // Term contains at least one such character.
+ try {
+ // Filter the starting anchor or wildcard character, if any.
+ String firstChar = filteredTermBuilder.substring(0,1);
+ switch (firstChar) {
+ case RepositoryJavaClientImpl.USER_SUPPLIED_ANCHOR_CHAR:
+ anchorAtStart = true;
+ break;
+ case RepositoryJavaClientImpl.USER_SUPPLIED_WILDCARD:
+ filteredTermBuilder.deleteCharAt(0);
+ break;
+ }
+ if (logger.isTraceEnabled()) {
+ logger.trace(String.format("After first char filtering = %s", filteredTermBuilder.toString()));
+ }
+ // Filter the ending anchor or wildcard character, if any.
+ int lastPos = filteredTermBuilder.length() - 1;
+ String lastChar = filteredTermBuilder.substring(lastPos);
+ switch (lastChar) {
+ case RepositoryJavaClientImpl.USER_SUPPLIED_ANCHOR_CHAR:
+ filteredTermBuilder.deleteCharAt(lastPos);
+ filteredTermBuilder.insert(filteredTermBuilder.length(), RepositoryJavaClientImpl.ENDING_ANCHOR_CHAR);
+ anchorAtEnd = true;
+ break;
+ case RepositoryJavaClientImpl.USER_SUPPLIED_WILDCARD:
+ filteredTermBuilder.deleteCharAt(lastPos);
+ break;
+ }
+ if (logger.isTraceEnabled()) {
+ logger.trace(String.format("After last char filtering = %s", filteredTermBuilder.toString()));
+ }
+ filteredTerm = filteredTermBuilder.toString();
+ // Filter all other wildcards, if any.
+ filteredTerm = filteredTerm.replaceAll(RepositoryJavaClientImpl.USER_SUPPLIED_WILDCARD_REGEX, ZERO_OR_MORE_ANY_CHAR_REGEX);
+ if (logger.isTraceEnabled()) {
+ logger.trace(String.format("After replacing user wildcards = %s", filteredTerm));
+ }
+ } catch (Exception e) {
+ logger.warn(String.format("Error filtering anchor and wildcard characters from string: %s", e.getMessage()));
+ return term;
+ }
+ }
+ // Wrap the term in beginning and ending regex wildcards, unless a
+ // starting or ending anchor character was present.
+ return (anchorAtStart ? "" : ZERO_OR_MORE_ANY_CHAR_REGEX)
+ + filteredTerm
+ + (anchorAtEnd ? "" : ZERO_OR_MORE_ANY_CHAR_REGEX);
+ }
+
@SuppressWarnings("unchecked")
private List<String> getPartialTermDisplayNameMatches(DocumentModel docModel, // REM - CSPACE-5133
String schema, ListResultField field, String partialTerm) {