org.ow2.util.substitution.resolver.RecursiveResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of util-substitution Show documentation
Show all versions of util-substitution Show documentation
Utility classes for properties substitution.
/**
* EasyBeans
* Copyright (C) 2010 Bull S.A.S.
* Contact: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: RecursiveResolver.java 5562 2010-08-12 12:24:45Z sauthieg $
* --------------------------------------------------------------------------
*/
package org.ow2.util.substitution.resolver;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.ow2.util.substitution.IPropertyResolver;
import org.ow2.util.substitution.ISubstitutionEngine;
/**
* @author Guillaume Sauthier
*/
public class RecursiveResolver implements IPropertyResolver {
/**
* Engine used to delegate recursion.
*/
private ISubstitutionEngine engine;
/**
* Delegating resolver.
*/
private IPropertyResolver delegate;
/**
* Processed Expressions.
*/
private Stack processedExpressions;
/**
* Intermediate resolutions.
*/
private Map resolutions;
/**
* Reports.
*/
private List reports;
/**
* Is this recursive resolver strict ?
*/
private boolean strict = true;
public RecursiveResolver(final ISubstitutionEngine engine,
final IPropertyResolver delegate) {
assert engine != null;
assert delegate != null;
this.engine = engine;
this.delegate = delegate;
this.processedExpressions = new Stack();
this.resolutions = new Hashtable();
this.reports = new ArrayList();
}
public boolean isStrict() {
return strict;
}
public void setStrict(boolean strict) {
this.strict = strict;
}
public List getReports() {
return reports;
}
public String resolve(final String expression) {
// Detect if we're going into a loop to prevent infinite recursion
if (isAlreadyProcessed(expression)) {
// Create a recursion report
Report report = createReport(expression);
this.reports.add(report);
// Throw exception if we're in strict mode
if (isStrict()) {
throw new IllegalArgumentException(report.toString());
}
// Return the resolved value with an "infinite" marker
return "[" + expression + ":infinite-loop]";
} else {
// Delegate resolution
String resolved = delegate.resolve(expression);
if (resolved == null) {
// Property could not be resolved
throw new IllegalArgumentException("Expression [" + expression + "] could not be resolved.");
}
// Recursive substitution of the resolved value
return doSubstitute(expression, resolved);
}
}
/**
* Perform a recursive substitution
* @param expression original expression
* @param resolved evaluated value of the expression (may contains variables)
* @return the substituted value of the resolution result
*/
private String doSubstitute(final String expression, final String resolved) {
// Store values
processedExpressions.push(expression);
resolutions.put(expression, resolved);
try {
// Perform substitution
return engine.substitute(resolved);
} finally {
// Do some clean-up
processedExpressions.pop();
resolutions.remove(expression);
}
}
private boolean isAlreadyProcessed(final String expression) {
return processedExpressions.contains(expression);
}
/**
* Create a report containing information about the recursion error.
* @param name infinite recursive expression
* @return a well formed Report
*/
private Report createReport(final String name) {
Report report = new Report();
report.expression = name;
// Store the resolution stack
report.resolutionStack = new Stack();
for (String element : processedExpressions) {
Resolution res = new Resolution(element, resolutions.get(element));
report.resolutionStack.push(res);
}
return report;
}
public static class Report {
private String expression;
private Stack resolutionStack;
public String getRecursiveExpression() {
return expression;
}
public Stack getResolutionStack() {
return resolutionStack;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Stopping infinite recursion loop on '");
sb.append(expression);
sb.append("'\n");
sb.append("Recursion stack\n");
int i = 0;
for (Resolution resolution : resolutionStack) {
sb.append(" ");
sb.append(i);
sb.append(". ");
sb.append(resolution.name);
sb.append(" -> ");
sb.append(resolution.value);
sb.append("\n");
i++;
}
return sb.toString();
}
}
/**
* Simple name/value pair class representation.
*/
public static class Resolution {
public Resolution(final String name, final String value) {
this.name = name;
this.value = value;
}
public String name;
public String value;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Resolution that = (Resolution) o;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
if (value != null ? !value.equals(that.value) : that.value != null) return false;
return true;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
}
}