Skip to content

Commit

Permalink
Accept default value in placeholders for unresolved property values (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
diamondT committed May 23, 2023
1 parent d9f1d82 commit 2a3ff69
Show file tree
Hide file tree
Showing 9 changed files with 513 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.codehaus.mojo.properties;

/*
* 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.
*/

/**
* ExpansionBuffer implementation that allows processing of default values within property placeholders
*
* @author tdiamantis
*/
public class DefaultValuesAwareExpansionBufferImpl extends ExpansionBuffer {
public DefaultValuesAwareExpansionBufferImpl(String unresolved) {
super(unresolved);
}

public KeyAndDefaultValue extractPropertyKeyAndDefaultValue()
{
advanceToNextPrefix();

discardPrefix();

String key = beforeNextSuffix();

String defaultValue = defaultValue();

discardToAfterNextSuffix();

return new KeyAndDefaultValue(key, defaultValue);
}

protected String beforeNextSuffix()
{
int defValuePos = unresolved.indexOf(":");
int propertySuffixPos = unresolved.indexOf("}");

//check default value separator only if before next suffix
if (defValuePos != -1 && propertySuffixPos != -1 && defValuePos < propertySuffixPos)
{
return unresolved.substring( 0, defValuePos );
}

return unresolved.substring( 0, propertySuffixPos );
}

private String defaultValue()
{
int defValuePos = unresolved.indexOf( ":" );
int propertySuffixPos = unresolved.indexOf( "}" );
if (defValuePos != -1 && propertySuffixPos != -1 && (defValuePos+1) < propertySuffixPos)
{
return unresolved.substring( defValuePos+1, propertySuffixPos );
}

return null;
}
}
29 changes: 7 additions & 22 deletions src/main/java/org/codehaus/mojo/properties/ExpansionBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
* under the License.
*/

class ExpansionBuffer
abstract class ExpansionBuffer
{
private final StringBuilder resolved = new StringBuilder();

private String unresolved;
protected String unresolved;

public ExpansionBuffer( String unresolved )
{
Expand All @@ -37,18 +37,7 @@ public boolean hasMoreLegalPlaceholders()
return prefixPos >= 0 && suffixPos >= 0;
}

public String extractPropertyKey()
{
advanceToNextPrefix();

discardPrefix();

String key = beforeNextSuffix();

discardToAfterNextSuffix();

return key;
}
public abstract KeyAndDefaultValue extractPropertyKeyAndDefaultValue();

public String toString()
{
Expand Down Expand Up @@ -82,18 +71,18 @@ private void skipUnresolvedPlaceholder( String newKey )
resolved.append( "${" ).append( newKey ).append( "}" );
}

private void discardToAfterNextSuffix()
protected void discardToAfterNextSuffix()
{
int propertySuffixPos = unresolved.indexOf( "}" );
unresolved = unresolved.substring( propertySuffixPos + 1 );
}

private void advanceToNextPrefix()
protected void advanceToNextPrefix()
{
resolved.append( beforePrefix() );
}

private void discardPrefix()
protected void discardPrefix()
{
int propertyPrefixPos = unresolved.indexOf( "${" );
unresolved = unresolved.substring( propertyPrefixPos + 2 );
Expand All @@ -105,9 +94,5 @@ private String beforePrefix()
return unresolved.substring( 0, propertyPrefixPos );
}

private String beforeNextSuffix()
{
int propertySuffixPos = unresolved.indexOf( "}" );
return unresolved.substring( 0, propertySuffixPos );
}
protected abstract String beforeNextSuffix();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.codehaus.mojo.properties;

/*
* 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.
*/

/**
* Default implementation of the ExpansionBuffer class
*
* @author tdiamantis
*/
public class ExpansionBufferImpl extends ExpansionBuffer {
public ExpansionBufferImpl(String unresolved) {
super(unresolved);
}

public KeyAndDefaultValue extractPropertyKeyAndDefaultValue()
{
advanceToNextPrefix();

discardPrefix();

String key = beforeNextSuffix();

discardToAfterNextSuffix();

return new KeyAndDefaultValue(key, null);
}

protected String beforeNextSuffix()
{
int propertySuffixPos = unresolved.indexOf( "}" );
return unresolved.substring( 0, propertySuffixPos );
}
}
49 changes: 49 additions & 0 deletions src/main/java/org/codehaus/mojo/properties/KeyAndDefaultValue.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.codehaus.mojo.properties;

/*
* 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.
*/

/**
* @author tdiamantis
*/
public class KeyAndDefaultValue {
private String key;
private String defaultValue;

public KeyAndDefaultValue(String key, String defaultValue) {
this.key = key;
this.defaultValue = defaultValue;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

public String getDefaultValue() {
return defaultValue;
}

public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
}
37 changes: 32 additions & 5 deletions src/main/java/org/codehaus/mojo/properties/PropertyResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,40 @@ class PropertyResolver
* @return resolved property value
* @throws IllegalArgumentException when properties are circularly defined
*/
public String getPropertyValue( String key, Properties properties, Properties environment )
public String getPropertyValue( String key, Properties properties, Properties environment ) {
return getPropertyValue(key, properties, environment, false);
}

/**
* Same as the previous method. Accepts an extra flag to indicate whether default values should be
* processed within property placeholders or not.
*
* @param key property key
* @param properties project properties
* @param environment environment variables
* @param useDefaultValues process default values flag
* @return resolved property value
* @throws IllegalArgumentException when properties are circularly defined
*/
public String getPropertyValue( String key, Properties properties, Properties environment, boolean useDefaultValues )
{
String value = properties.getProperty( key );

ExpansionBuffer buffer = new ExpansionBuffer( value );
ExpansionBuffer buffer;
if ( useDefaultValues ) {
buffer = new DefaultValuesAwareExpansionBufferImpl(value);
} else {
buffer = new ExpansionBufferImpl( value );
}

CircularDefinitionPreventer circularDefinitionPreventer =
new CircularDefinitionPreventer().visited( key, value );

while ( buffer.hasMoreLegalPlaceholders() )
{
String newKey = buffer.extractPropertyKey();
String newValue = fromPropertiesThenSystemThenEnvironment( newKey, properties, environment );
KeyAndDefaultValue kv = buffer.extractPropertyKeyAndDefaultValue();
String newKey = kv.getKey();
String newValue = fromPropertiesThenSystemThenEnvironment( newKey, kv.getDefaultValue(), properties, environment );

circularDefinitionPreventer.visited( newKey, newValue );

Expand All @@ -60,7 +81,7 @@ public String getPropertyValue( String key, Properties properties, Properties en
return buffer.toString();
}

private String fromPropertiesThenSystemThenEnvironment( String key, Properties properties, Properties environment )
private String fromPropertiesThenSystemThenEnvironment( String key, String defaultValue, Properties properties, Properties environment )
{
String value = properties.getProperty( key );

Expand All @@ -76,6 +97,12 @@ private String fromPropertiesThenSystemThenEnvironment( String key, Properties p
value = environment.getProperty( key.substring( 4 ) );
}

// try default value
if ( value == null )
{
value = defaultValue;
}

return value;
}
}
34 changes: 29 additions & 5 deletions src/main/java/org/codehaus/mojo/properties/ReadPropertiesMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void setFiles( File[] files )

/**
* Default scope for test access.
*
*
* @param urls The URLs to set for tests.
*/
public void setUrls( String[] urls )
Expand Down Expand Up @@ -122,6 +122,14 @@ public void setKeyPrefix( String keyPrefix )
@Parameter( defaultValue = "false", property = "prop.skipLoadProperties" )
private boolean skipLoadProperties;

/**
* If the plugin should process default values within property placeholders
*
* @parameter default-value="false"
*/
@Parameter( defaultValue = "false" )
private boolean useDefaultValues;

/**
* Used for resolving property placeholders.
*/
Expand Down Expand Up @@ -278,7 +286,7 @@ private String getPropertyValue( String k, Properties p, Properties environment
{
try
{
return resolver.getPropertyValue( k, p, environment );
return resolver.getPropertyValue( k, p, environment , useDefaultValues);
}
catch ( IllegalArgumentException e )
{
Expand All @@ -288,7 +296,7 @@ private String getPropertyValue( String k, Properties p, Properties environment

/**
* Override-able for test purposes.
*
*
* @return The shell environment variables, can be empty but never <code>null</code>.
* @throws IOException If the environment variables could not be queried from the shell.
*/
Expand All @@ -300,7 +308,7 @@ Properties getSystemEnvVars()

/**
* Default scope for test access.
*
*
* @param quiet Set to <code>true</code> if missing files can be skipped.
*/
void setQuiet( boolean quiet )
Expand All @@ -317,16 +325,32 @@ void setSkipLoadProperties( boolean skipLoadProperties )
this.skipLoadProperties = skipLoadProperties;
}

/**
* @param useDefaultValues set to <code>true</code> if default values need to be processed within property placeholders
*/
public void setUseDefaultValues(boolean useDefaultValues)
{
this.useDefaultValues = useDefaultValues;
}

/**
* Default scope for test access.
*
*
* @param project The test project.
*/
void setProject( MavenProject project )
{
this.project = project;
}

/**
* For test access.
* @return The test project
*/
public MavenProject getProject() {
return project;
}

private static abstract class Resource
{
private InputStream stream;
Expand Down

0 comments on commit 2a3ff69

Please sign in to comment.