Skip to content
Permalink
Browse files
Adding expression evaluator
  • Loading branch information
effrafax committed Oct 17, 2019
1 parent 318b406 commit a054f7b9f952158da70fadd94eda448e36c0dc13
Showing 10 changed files with 729 additions and 0 deletions.
@@ -0,0 +1,10 @@
.idea/**
.project
.classpath
.settings
.java-version
target
.DS_Store
.site-content
out
*.iml
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you 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
~
~ http://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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.apache.archiva.components</groupId>
<artifactId>archiva-components</artifactId>
<version>3.0-SNAPSHOT</version>
</parent>

<version>3.0-SNAPSHOT</version>
<artifactId>archiva-components-expression-evaluator</artifactId>
<name>Archiva Components :: Expression Evaluator</name>

<properties>
<site.staging.base>${project.basedir}/..</site.staging.base>
</properties>


<url>${webUrl}/${project.artifactId}</url>

<scm>
<url>${scmBrowseUrl}</url>
</scm>


<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>

</project>
@@ -0,0 +1,159 @@
package org.apache.archiva.components.evaluator;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.
*/

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* DefaultExpressionEvaluator
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
*
*/
public class DefaultExpressionEvaluator
implements ExpressionEvaluator
{
private List<ExpressionSource> expressionSources;

public DefaultExpressionEvaluator()
{
expressionSources = new ArrayList<>();
}

public void addExpressionSource( ExpressionSource source )
{
expressionSources.add( source );
}

public String expand( String str )
throws EvaluatorException
{
return recursiveExpand( str, new ArrayList<String>() );
}

private String recursiveExpand( String str, List<String> seenExpressions )
throws EvaluatorException
{
if ( StringUtils.isEmpty( str ) )
{
// Empty string. Fail fast.
return str;
}

if ( str.indexOf( "${" ) < 0 )
{
// Contains no potential expressions. Fail fast.
return str;
}

if ( this.expressionSources.isEmpty() )
{
throw new EvaluatorException( "Unable to expand expressions with empty ExpressionSource list." );
}

Pattern pat = Pattern.compile( "(?<=[^$]|^)(\\$\\{[^}]*\\})" );
Matcher mat = pat.matcher( str );
int offset = 0;
String expression;
String value;
StringBuilder expanded = new StringBuilder();

while ( mat.find( offset ) )
{
expression = mat.group( 1 );

if ( seenExpressions.contains( expression ) )
{
throw new EvaluatorException( "A recursive cycle has been detected with expression " + expression + "." );
}

seenExpressions.add( expression );

expanded.append( str.substring( offset, mat.start( 1 ) ) );
value = findValue( expression );
if ( value != null )
{
String resolvedValue = recursiveExpand( value, seenExpressions );
expanded.append( resolvedValue );
}
else
{
expanded.append( expression );
}
offset = mat.end( 1 );
}

expanded.append( str.substring( offset ) );

if ( expanded.indexOf( "$$" ) >= 0 )
{
// Special case for escaped content.
return expanded.toString().replaceAll( "\\$\\$", "\\$" );
}
else
{
// return expanded
return expanded.toString();
}
}

private String findValue( String expression )
{
String newExpression = expression.trim();
if ( newExpression.startsWith( "${" ) && newExpression.endsWith( "}" ) )
{
newExpression = newExpression.substring( 2, newExpression.length() - 1 );
}

if ( StringUtils.isEmpty( newExpression ) )
{
return null;
}

String value = null;
Iterator it = this.expressionSources.iterator();
while ( it.hasNext() )
{
ExpressionSource source = (ExpressionSource) it.next();
value = source.getExpressionValue( newExpression );
if ( value != null )
{
return value;
}
}
return null;
}

public List getExpressionSourceList()
{
return this.expressionSources;
}

public boolean removeExpressionSource( ExpressionSource source )
{
return this.expressionSources.remove( source );
}
}
@@ -0,0 +1,50 @@
package org.apache.archiva.components.evaluator;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.
*/

/**
* EvaluatorException
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
*
*/
public class EvaluatorException
extends Exception
{
public EvaluatorException()
{
super();
}

public EvaluatorException( String message, Throwable cause )
{
super( message, cause );
}

public EvaluatorException( String message )
{
super( message );
}

public EvaluatorException( Throwable cause )
{
super( cause );
}
}
@@ -0,0 +1,63 @@
package org.apache.archiva.components.evaluator;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.
*/

import java.util.List;

/**
* ExpressionEvaluator
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
*
*/
public interface ExpressionEvaluator
{
/**
* Add a source for expression resolution.
*
* @param source the source to add.
*/
void addExpressionSource( ExpressionSource source );

/**
* Evaluate a string, and expand expressions as needed.
*
* @param str the expression
* @return the value of the expression
* @throws EvaluatorException if a problem occurs whilst evaluating
*/
String expand( String str )
throws EvaluatorException;

/**
* Get the List of expression sources.
*
* @return the list of expression sources.
*/
List getExpressionSourceList();

/**
* Remove a specific expression source.
*
* @param source the source to remove.
* @return true if expression source was removed.
*/
boolean removeExpressionSource( ExpressionSource source );
}
@@ -0,0 +1,37 @@
package org.apache.archiva.components.evaluator;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* http://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.
*/

/**
* ExpressionSource
*
* @author <a href="mailto:joakim@erdfelt.com">Joakim Erdfelt</a>
*
*/
public interface ExpressionSource
{
/**
* Gets a value for a provided Expression.
*
* @param expression the expression to attempt to get a value for.
* @return the value for the expression, or null if no value found.
*/
String getExpressionValue( String expression );
}

0 comments on commit a054f7b

Please sign in to comment.