/*******************************************************************************
* Copyright (c) 2004, 2010 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.rc.common.util;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.apache.oro.text.GlobCompiler;
import org.apache.oro.text.regex.MalformedPatternException;
import org.apache.oro.text.regex.MatchResult;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternCompiler;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import org.eclipse.jubula.rc.common.exception.StepExecutionException;
import org.eclipse.jubula.toolkit.enums.ValueSets.Operator;
import org.eclipse.jubula.tools.internal.constants.StringConstants;
import org.eclipse.jubula.tools.internal.objects.event.EventFactory;
import org.eclipse.jubula.tools.internal.objects.event.TestErrorEvent;
/**
* Utility class for string matching operations
*
* @author BREDEX GmbH
* @created 02.12.2005
*/
public class MatchUtil {
/**
*
* Helper class to return a string and its position
*
*/
public static class FindResult {
/** Position of pattern in string */
private int m_pos;
/** string matching pattern */
private String m_str;
/**
* Store data
* @param str string matching pattern
* @param pos Position of pattern in string
*/
public FindResult(String str, int pos) {
m_str = str;
m_pos = pos;
}
/**
* @return the pos
*/
public int getPos() {
return m_pos;
}
/**
* @return the str
*/
public String getStr() {
return m_str;
}
}
/**
* A match operation
*/
private interface MatchOperation {
/**
* Checks if <code>text</code> matches <code>pattern</code>
*
* @param text
* a text
* @param pattern
* a pattern
* @return
* <code>true</code> if <code>text</code> matches
* <code>pattern</code>.
*/
public boolean matches(String text, String pattern);
}
/**
* A match operation
*/
private interface FindOperation {
/**
* Checks if <code>text</code> matches <code>pattern</code>
*
* @param text
* a text
* @param pattern
* a pattern
* @return
* position and value of match
*/
public FindResult find(String text, String pattern);
}
/**
* match if text equals pattern
*/
public static final String EQUALS = Operator.equals.rcValue();
/**
* match if text and pattern are not equal
*/
public static final String NOT_EQUALS = Operator.notEquals.rcValue();
/**
* match if text matches a regexp pattern
*/
public static final String MATCHES_REGEXP = Operator.matches.rcValue();
/**
* match if text matches a Unix-style glob pattern
*/
public static final String MATCHES_GLOB = Operator.simpleMatch.rcValue();
/**
* default operator
*/
public static final String DEFAULT_OPERATOR = EQUALS;
/**
* <code>MatchUtil</code> instance
*/
private static MatchUtil instance = new MatchUtil();
/**
* Maps operators to operations
*/
private Map<String, MatchOperation> m_operationMap =
new HashMap<String, MatchOperation>();
/**
* Maps operators to operations
*/
private Map<String, FindOperation> m_findOperationMap =
new HashMap<String, FindOperation>();
/**
* forbid construction
*/
private MatchUtil() {
m_operationMap.put(EQUALS, new MatchOperation() {
public boolean matches(String text, String pattern) {
return isEqual(text, pattern);
}
});
m_operationMap.put(NOT_EQUALS, new MatchOperation() {
public boolean matches(String text, String pattern) {
return !isEqual(text, pattern);
}
});
m_operationMap.put(MATCHES_REGEXP, new MatchOperation() {
public boolean matches(String text, String pattern) {
return matchesRegExp(text, pattern);
}
});
m_operationMap.put(MATCHES_GLOB, new MatchOperation() {
public boolean matches(String text, String pattern) {
return matchesGlob(text, pattern);
}
});
m_findOperationMap.put(EQUALS, new FindOperation() {
public FindResult find(String text, String pattern) {
int index = text.indexOf(pattern);
return new FindResult(index != -1 ? pattern : null, index);
}
});
m_findOperationMap.put(NOT_EQUALS, new FindOperation() {
public FindResult find(String text, String pattern) {
int index = text.indexOf(pattern);
return new FindResult(index != -1 ? pattern : null, index);
}
});
m_findOperationMap.put(MATCHES_REGEXP, new FindOperation() {
public FindResult find(String text, String pattern) {
return findRegExp(text, pattern);
}
});
m_findOperationMap.put(MATCHES_GLOB, new FindOperation() {
public FindResult find(String text, String pattern) {
return findGlob(text, pattern);
}
});
}
/**
* Returns the <code>MatchUtil</code> instance
*
* @return
* the <code>MatchUtil</code> instance
*/
public static MatchUtil getInstance() {
return instance;
}
/**
* Checks if <code>text</code> matches <code>pattern</code>.
*
* @param text
* a text
* @param pattern
* a pattern
* @param operator
* operator used for matching
* @return
* position and value of match
* @throws StepExecutionException
* if the operator is not known
*/
public FindResult find(String text, String pattern, String operator)
throws StepExecutionException {
if (!m_findOperationMap.containsKey(operator)) {
TestErrorEvent event = EventFactory.createActionError(
TestErrorEvent.UNKNOWN_OPERATOR, new Object[] { operator });
throw new StepExecutionException("unknown operator", event); //$NON-NLS-1$
}
if (pattern == null) {
TestErrorEvent event = EventFactory.createActionError(
TestErrorEvent.MALFORMED_REGEXP, new Object[] { pattern });
throw new StepExecutionException("null pattern", event); //$NON-NLS-1$
}
FindOperation op = m_findOperationMap.get(operator);
return op.find(text == null ? StringConstants.EMPTY : text, pattern);
}
/**
* Checks if <code>text</code> matches <code>pattern</code>.
*
* @param text
* a text
* @param pattern
* a pattern
* @param operator
* operator used for matching
* @return
* <code>true</code> if <code>text</code> matches
* <code>pattern</code>
* @throws StepExecutionException
* if the operator is not known
*/
public boolean match(String text, String pattern, String operator)
throws StepExecutionException {
if (!m_operationMap.containsKey(operator)) {
TestErrorEvent event = EventFactory.createActionError(
TestErrorEvent.UNKNOWN_OPERATOR, new Object[] { operator });
throw new StepExecutionException("unknown operator", event); //$NON-NLS-1$
}
MatchOperation op = m_operationMap.get(operator);
return op.matches(text == null ? StringConstants.EMPTY : text, pattern);
}
/**
* Checks if <code>text</code> matches one of the patterns.
* for equals and match-operator return true, if one of the given patterns
* matches the given text (logical or)
* for notequals-operator returns true, if all given patterns not match the
* given text (logical and)
*
* @param text
* a text
* @param patterns
* several patterns
* @param operator
* operator used for matching
* @return
* <code>true</code> if <code>text</code> matches a pattern
* @throws StepExecutionException
* if the operator is not known
*/
public boolean match(String text, String[] patterns, String operator)
throws StepExecutionException {
boolean result = true;
for (int i = 0; i < patterns.length; ++i) {
if (operator.startsWith("not")) { //$NON-NLS-1$
// logical and for each pattern and use of not equals-operator
if (!(match(text, patterns[i], operator))) {
result = false;
break;
}
// logical or for each pattern and use of equals-/matches-operator
} else {
if (match(text, patterns[i], operator)) {
result = true;
break;
}
result = false;
}
}
return result;
}
/**
* Returns <code>true</code> if both strings are equal
*
* @param text
* a text
* @param pattern
* a pattern
* @return
* <code>true</code> if both strings are equal
*/
private boolean isEqual(String text, String pattern) {
return StringUtils.equals(text, pattern);
}
/**
* Returns <code>true</code> if <code>text</code> matches the
* regular expression <code>pattern</code>
*
* @param text
* a text
* @param pattern
* a pattern
* @return
* <code>true</code> if <code>text</code> matches
* <code>pattern</code>
*/
private boolean matchesRegExp(String text, String pattern) {
PatternCompiler pc = new Perl5Compiler();
PatternMatcher matcher = new Perl5Matcher();
try {
Pattern p = pc.compile(pattern, Perl5Compiler.SINGLELINE_MASK);
return matcher.matches(text, p);
} catch (MalformedPatternException exc) {
TestErrorEvent event = EventFactory.createActionError(
TestErrorEvent.MALFORMED_REGEXP, new Object[] { pattern });
throw new StepExecutionException("malformed regular expression", //$NON-NLS-1$
event);
}
}
/**
* Returns <code>true</code> if <code>text</code> matches the
* glob <code>pattern</code>
*
* @param text
* a text
* @param pattern
* a pattern
* @return
* <code>true</code> if <code>text</code> matches
* <code>pattern</code>
*/
private boolean matchesGlob(String text, String pattern) {
return matchesRegExp(text, GlobCompiler.globToPerl5(pattern
.toCharArray(), GlobCompiler.DEFAULT_MASK));
}
/**
* Returns <code>text</code> matches the
* regular expression <code>pattern</code>
*
* @param text
* a text
* @param pattern
* a pattern
* @return
* value and position of match
*/
private FindResult findRegExp(String text, String pattern) {
PatternCompiler pc = new Perl5Compiler();
PatternMatcher matcher = new Perl5Matcher();
try {
Pattern p = pc.compile(pattern, Perl5Compiler.SINGLELINE_MASK);
matcher.contains(text, p);
MatchResult match = matcher.getMatch();
if (match != null) {
return new FindResult(match.toString(),
match.beginOffset(0));
}
return null;
} catch (MalformedPatternException exc) {
TestErrorEvent event = EventFactory.createActionError(
TestErrorEvent.MALFORMED_REGEXP, new Object[] { pattern });
throw new StepExecutionException("malformed regular expression", //$NON-NLS-1$
event);
}
}
/**
* Returns <code>text</code> matches the
* glob <code>pattern</code>
*
* @param text
* a text
* @param pattern
* a pattern
* @return
* value and position of match
*/
private FindResult findGlob(String text, String pattern) {
return findRegExp(text, GlobCompiler.globToPerl5(pattern.toCharArray(),
GlobCompiler.DEFAULT_MASK));
}
}