All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.classify.PatternMatcher Maven / Gradle / Ivy

Go to download

Spring Retry provides an abstraction around retrying failed operations, with an emphasis on declarative control of the process and policy-based behaviour that is easy to extend and customize. For instance, you can configure a plain POJO operation to retry if it fails, based on the type of exception, and with a fixed or exponential backoff.

There is a newer version: 2.0.10
Show newest version
/*
 * Copyright 2006-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.classify;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.util.Assert;

/**
 * @author Dave Syer
 * @author Dan Garrette
 * @param  the type of the thing to match a pattern on
 */
public class PatternMatcher {

	private Map map = new HashMap<>();

	private List sorted = new ArrayList<>();

	/**
	 * Initialize a new {@link PatternMatcher} with a map of patterns to values
	 * @param map a map from String patterns to values
	 */
	public PatternMatcher(Map map) {
		super();
		this.map = map;
		// Sort keys to start with the most specific
		this.sorted = new ArrayList<>(map.keySet());
		this.sorted.sort((o1, o2) -> {
			String s1 = o1; // .replace('?', '{');
			String s2 = o2; // .replace('*', '}');
			return s2.compareTo(s1);
		});
	}

	/**
	 * Lifted from AntPathMatcher in Spring Core. Tests whether or not a string matches
	 * against a pattern. The pattern may contain two special characters:
* '*' means zero or more characters
* '?' means one and only one character * @param pattern pattern to match against. Must not be null. * @param str string which must be matched against the pattern. Must not be * null. * @return true if the string matches against the pattern, or * false otherwise. */ public static boolean match(String pattern, String str) { char[] patArr = pattern.toCharArray(); char[] strArr = str.toCharArray(); int patIdxStart = 0; int patIdxEnd = patArr.length - 1; int strIdxStart = 0; int strIdxEnd = strArr.length - 1; char ch; boolean containsStar = pattern.contains("*"); if (!containsStar) { // No '*'s, so we make a shortcut if (patIdxEnd != strIdxEnd) { return false; // Pattern and string do not have the same size } for (int i = 0; i <= patIdxEnd; i++) { ch = patArr[i]; if (ch != '?') { if (ch != strArr[i]) { return false;// Character mismatch } } } return true; // String matches against pattern } if (patIdxEnd == 0) { return true; // Pattern contains only '*', which matches anything } // Process characters before first star while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { if (ch != '?') { if (ch != strArr[strIdxStart]) { return false;// Character mismatch } } patIdxStart++; strIdxStart++; } if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { if (patArr[i] != '*') { return false; } } return true; } // Process characters after last star while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { if (ch != '?') { if (ch != strArr[strIdxEnd]) { return false;// Character mismatch } } patIdxEnd--; strIdxEnd--; } if (strIdxStart > strIdxEnd) { // All characters in the string are used. Check if only '*'s are // left in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { if (patArr[i] != '*') { return false; } } return true; } // process pattern between stars. padIdxStart and patIdxEnd point // always to a '*'. while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { int patIdxTmp = -1; for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { if (patArr[i] == '*') { patIdxTmp = i; break; } } if (patIdxTmp == patIdxStart + 1) { // Two stars next to each other, skip the first one. patIdxStart++; continue; } // Find the pattern between padIdxStart & padIdxTmp in str between // strIdxStart & strIdxEnd int patLength = (patIdxTmp - patIdxStart - 1); int strLength = (strIdxEnd - strIdxStart + 1); int foundIdx = -1; strLoop: for (int i = 0; i <= strLength - patLength; i++) { for (int j = 0; j < patLength; j++) { ch = patArr[patIdxStart + j + 1]; if (ch != '?') { if (ch != strArr[strIdxStart + i + j]) { continue strLoop; } } } foundIdx = strIdxStart + i; break; } if (foundIdx == -1) { return false; } patIdxStart = patIdxTmp; strIdxStart = foundIdx + patLength; } // All characters in the string are used. Check if only '*'s are left // in the pattern. If so, we succeeded. Otherwise failure. for (int i = patIdxStart; i <= patIdxEnd; i++) { if (patArr[i] != '*') { return false; } } return true; } /** *

* This method takes a String key and a map from Strings to values of any type. During * processing, the method will identify the most specific key in the map that matches * the line. Once the correct is identified, its value is returned. Note that if the * map contains the wildcard string "*" as a key, then it will serve as the "default" * case, matching every line that does not match anything else. * *

* If no matching prefix is found, a {@link IllegalStateException} will be thrown. * *

* Null keys are not allowed in the map. * @param line An input string * @return the value whose prefix matches the given line */ public S match(String line) { S value = null; Assert.notNull(line, "A non-null key must be provided to match against."); for (String key : this.sorted) { if (PatternMatcher.match(key, line)) { value = this.map.get(key); break; } } if (value == null) { throw new IllegalStateException("Could not find a matching pattern for key=[" + line + "]"); } return value; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy