LocaleURLMatcher.java

/*
 * Copyright 2026 Global Crop Diversity Trust
 * Licensed under the Apache License, Version 2.0
 * See LICENSE file in project root folder or http://www.apache.org/licenses/LICENSE-2.0
 */

package org.gringlobal.spring.locale;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lombok.extern.slf4j.Slf4j;



/**
 * The Class LocaleURLMatcher.
 */
@Slf4j
public class LocaleURLMatcher {
	private static final Pattern localePattern = Pattern.compile("^/([a-z]{2}(?:\\-[a-z]{2})?)(/.*)");
	private String[] excludedPaths;

	public void setExcludedPaths(String[] excludedPaths) {
		this.excludedPaths = excludedPaths;
	}

	public boolean isExcludedPath(String url) {
		for (String excludedPath : excludedPaths) {
			if (url.startsWith(excludedPath)) {
				if (log.isDebugEnabled()) {
					log.debug("Excluded: {} matches {}", excludedPath, url);
				}
				return true;
			}
		}

		return false;
	}

	public boolean isExcluded(String url) {
		for (String excludedPath : excludedPaths) {
			if (url.startsWith(excludedPath)) {
				if (log.isDebugEnabled()) {
					log.debug("Excluded: {} matches {}", excludedPath, url);
				}
				return true;
			}
		}

		if (fastCheck(url)) {
			return true;
		}

		return false;
	}

	private boolean fastCheck(String url) {
		char[] dst = new char[7];
		url.getChars(0, Math.min(url.length(), 7), dst, 0);

		// Check language
		if (dst[0] != '/')
			return false;
		if (dst[1] < 'a' || dst[1] > 'z')
			return false;
		if (dst[2] < 'a' || dst[2] > 'z')
			return false;

		// end processing
		if (dst[3] == '/')
			return true;

		// Check country
		if (dst[3] != '-')
			return false;
		if (dst[4] < 'a' || dst[4] > 'z')
			return false;
		if (dst[5] < 'a' || dst[5] > 'z')
			return false;

		if (dst[6] != '/')
			return false;

		return true;
	}

	public Matcher matcher(String url) {
		return localePattern.matcher(url);
	}

}