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

org.refcodes.matcher.impls.PathMatcherImpl Maven / Gradle / Ivy

There is a newer version: 3.3.9
Show newest version
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// =============================================================================
// This code is copyright (c) by Siegfried Steiner, Munich, Germany and licensed
// under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// =============================================================================
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// together with the GPL linking exception applied; as being applied by the GNU
// Classpath ("http://www.gnu.org/software/classpath/license.html")
// =============================================================================
// Apache License, v2.0 ("http://www.apache.org/licenses/LICENSE-2.0")
// =============================================================================
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.matcher.impls;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import org.refcodes.data.Delimiter;
import org.refcodes.matcher.Matcher;
import org.refcodes.matcher.PathMatcher;
import org.refcodes.matcher.WildcardSubstitutes;

/**
 * Implements the {@link PathMatcher} interface.
 */
public class PathMatcherImpl implements PathMatcher {

	// /////////////////////////////////////////////////////////////////////////
	// CONSTANTS:
	// /////////////////////////////////////////////////////////////////////////

	private static final String WILDCARD_NAME_PATTERN = "(?<=\\$\\{).*?(?=\\}\\=)"; // ${name}=
	private static final int WILDCARD_NAME_PREFIX_LENGTH = 2; // "${"
	private static final int WILDCARD_NAME_SUFFIX_LENGTH = 2; // "}="
	private static final String WILDCARD_ASTERISK = "([^\\/]*)";
	private static final String WILDCARD_DOUBOLE_ASTERISK = "(.*)";
	private static final String WILDCARD_QUESTION_MARK = "(\\\\w)";
	private static final String REGEX_SAFE_SLASH = "\\/";
	private static final String REGEX_SAFE_DOT = "\\.";

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	private Pattern _matchee;
	private String _pathPattern = null;
	private String[] _wildcardNames = null;

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTORS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Constructs an ANT Path {@link Matcher}, matching its ANT path pattern
	 * against the path provided to the {@link #isMatching(String)} method.
	 * 
	 * The {@link Delimiter#PATH_DELIMITER} is used as default path delimiter.
	 * 
	 * The {@link PathMatcherImpl} applies the following rules from the ANT path
	 * pattern to the path provided via {@link #isMatching(String)} method:
	 * 
	 * A single asterisk ("*") matches zero or more characters within a path
	 * name. A double asterisk ("**") matches zero or more characters across
	 * directory levels. A question mark ("?") matches exactly one character
	 * within a path name.
	 * 
	 * @param aPathPattern The pattern to be used when matching a path via
	 *        {@link #isMatching(String)}.
	 */
	public PathMatcherImpl( String aPathPattern ) {
		assert (aPathPattern != null);
		_pathPattern = aPathPattern;
		// Convert the wildcards into regex pattern groups -->
		String theRegex = aPathPattern;
		theRegex = aPathPattern.replaceAll( "/", REGEX_SAFE_SLASH );
		theRegex = theRegex.replaceAll( "\\.", REGEX_SAFE_DOT );
		theRegex = theRegex.replaceAll( "(?
		Pattern theJokerPattern = Pattern.compile( WILDCARD_NAME_PATTERN );
		java.util.regex.Matcher eJokerMatcher = theJokerPattern.matcher( theRegex );
		String eTruncated, eName, eHead, eTail;
		String theAsterisk = WILDCARD_ASTERISK.replaceAll( "\\\\", "" );
		String theDoubleAsterisk = WILDCARD_DOUBOLE_ASTERISK.replaceAll( "(\\\\)\\\\", "$1" );
		String theQuestionMark = WILDCARD_QUESTION_MARK.replaceAll( "(\\\\)\\\\", "$1" );
		List theWildcardNames = new ArrayList<>();
		while ( eJokerMatcher.find() ) {
			eTruncated = theRegex.substring( eJokerMatcher.end() + WILDCARD_NAME_SUFFIX_LENGTH );
			if ( !eTruncated.startsWith( theAsterisk ) && !eTruncated.startsWith( theDoubleAsterisk ) && !eTruncated.startsWith( theQuestionMark ) ) { throw new IllegalArgumentException( "Your wildcard name (such as \"" + theRegex.substring( eJokerMatcher.start(), eJokerMatcher.start() ) + "\") in pattern <" + aPathPattern + "> must prefix a wildcard such as \"" + theAsterisk + "\" or \"" + theDoubleAsterisk + "\" or \"" + theQuestionMark + "!" ); }
			eName = theRegex.substring( eJokerMatcher.start(), eJokerMatcher.end() );
			theWildcardNames.add( eName );
			eHead = theRegex.substring( 0, eJokerMatcher.start() - WILDCARD_NAME_PREFIX_LENGTH );
			eTail = theRegex.substring( eJokerMatcher.end() + WILDCARD_NAME_SUFFIX_LENGTH );
			eTail = eTail.substring( 0, 1 ) + "?<" + eName + ">" + eTail.substring( 1 );
			theRegex = eHead + eTail;
			eJokerMatcher = theJokerPattern.matcher( theRegex );
		}
		if ( theWildcardNames.size() != 0 ) {
			_wildcardNames = theWildcardNames.toArray( new String[theWildcardNames.size()] );
		}
		// <-- Convert the wildcard names into regex pattern group names

		_matchee = Pattern.compile( theRegex );
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	@Override
	public String[] getWildcardNames() {
		return _wildcardNames;
	}

	@Override
	public String getPathPattern() {
		return _pathPattern;
	}

	@Override
	public boolean isMatching( String aPath ) {
		return _matchee.matcher( aPath ).matches();
	}

	@Override
	public WildcardSubstitutes toWildcardSubstitutes( String aPath ) {
		java.util.regex.Matcher theMatcher = _matchee.matcher( aPath );
		if ( !theMatcher.matches() ) return null;

		// Unnamed substitutes -->
		List theWildcardSubstitutes = new ArrayList<>();
		for ( int i = 0; i < theMatcher.groupCount(); i++ ) {
			theWildcardSubstitutes.add( theMatcher.group( i + 1 ) );
		}
		String[] theWildcardReplacements = theWildcardSubstitutes.toArray( new String[theWildcardSubstitutes.size()] );
		// <-- Unnamed substitutes

		// Named substitutes -->
		Map theNamedWildcardSubstitutes = null;
		if ( _wildcardNames != null ) {
			theNamedWildcardSubstitutes = new HashMap<>();
			for ( String eName : _wildcardNames ) {
				theNamedWildcardSubstitutes.put( eName, theMatcher.group( eName ) );
			}
		}
		// <-- Named substitutes

		return new WildcardSubstitutesImpl( theWildcardReplacements, theNamedWildcardSubstitutes );
	}

	@Override
	public String[] toWildcardReplacements( String aPath ) {
		java.util.regex.Matcher theMatcher = _matchee.matcher( aPath );
		if ( !theMatcher.matches() ) return null;
		List theWildcardSubstitutes = new ArrayList<>();
		for ( int i = 0; i < theMatcher.groupCount(); i++ ) {
			theWildcardSubstitutes.add( theMatcher.group( i + 1 ) );
		}
		return theWildcardSubstitutes.toArray( new String[theWildcardSubstitutes.size()] );
	}

	@Override
	public String toWildcardReplacementAt( String aPath, int aIndex ) {
		java.util.regex.Matcher theMatcher = _matchee.matcher( aPath );
		if ( !theMatcher.matches() ) return null;
		if ( aIndex < theMatcher.groupCount() ) return theMatcher.group( aIndex + 1 );
		throw new IllegalArgumentException( "Your provided index <" + aIndex + "> exceeds the number if wildcards <" + theMatcher.groupCount() + "> defined in your pattern \"" + getPathPattern() + "\" for current path \"" + aPath + "\"." );
	}

	@Override
	public String[] toWildcardReplacementsAt( String aPath, int... aIndexes ) {
		java.util.regex.Matcher theMatcher = _matchee.matcher( aPath );
		if ( !theMatcher.matches() ) return null;
		if ( aIndexes == null || aIndexes.length == 0 ) return new String[] {};
		List theWildcardSubstitutes = new ArrayList<>();
		for ( int i : aIndexes ) {
			if ( i >= theMatcher.groupCount() ) { throw new IllegalArgumentException( "Your provided index <" + i + "> exceeds the number of wildcards <" + theMatcher.groupCount() + "> defined in your pattern \"" + getPathPattern() + "\" for current path \"" + aPath + "\"." ); }
			theWildcardSubstitutes.add( theMatcher.group( i + 1 ) );
		}
		return theWildcardSubstitutes.toArray( new String[theWildcardSubstitutes.size()] );
	}

	@Override
	public String toWildcardReplacement( String aPath, String aWildcardName ) {
		java.util.regex.Matcher theMatcher = _matchee.matcher( aPath );
		if ( !theMatcher.matches() ) return null;
		try {
			return theMatcher.group( aWildcardName );
		}
		catch ( IllegalArgumentException e ) {
			throw new IllegalArgumentException( "Your provided name <" + aWildcardName + "> is not defined in your pattern \"" + getPathPattern() + "\" for current path \"" + aPath + "\".", e );
		}
	}

	@Override
	public String[] toWildcardReplacements( String aPath, String... aWildcardNames ) {
		java.util.regex.Matcher theMatcher = _matchee.matcher( aPath );
		if ( !theMatcher.matches() ) return null;
		if ( aWildcardNames == null || aWildcardNames.length == 0 ) return new String[] {};
		List theWildcardSubstitutes = new ArrayList<>();
		for ( String eWildcardName : aWildcardNames ) {
			try {
				theWildcardSubstitutes.add( theMatcher.group( eWildcardName ) );
			}
			catch ( IllegalArgumentException e ) {
				throw new IllegalArgumentException( "Your provided name <" + eWildcardName + "> is not defined in your pattern \"" + getPathPattern() + "\" for current path \"" + aPath + "\".", e );
			}
		}
		return theWildcardSubstitutes.toArray( new String[theWildcardSubstitutes.size()] );
	}

	/**
	 * For debugging purposes, retrieve the regex pattern created from the ANT
	 * path pattern.
	 * 
	 * @return Returns the regex created from the ANT path pattern.
	 */
	public String toPattern() {
		return _matchee.pattern();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((_matchee == null) ? 0 : _matchee.hashCode());
		return result;
	}

	@Override
	public boolean equals( Object obj ) {
		if ( this == obj ) return true;
		if ( obj == null ) return false;
		if ( getClass() != obj.getClass() ) return false;
		PathMatcherImpl other = (PathMatcherImpl) obj;
		if ( _matchee == null ) {
			if ( other._matchee != null ) return false;
		}
		else if ( !_matchee.equals( other._matchee ) ) return false;
		return true;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy