diff options
Diffstat (limited to 'framework/src/maven/apache-maven-3.3.3/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java')
-rw-r--r-- | framework/src/maven/apache-maven-3.3.3/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java | 504 |
1 files changed, 504 insertions, 0 deletions
diff --git a/framework/src/maven/apache-maven-3.3.3/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java b/framework/src/maven/apache-maven-3.3.3/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java new file mode 100644 index 00000000..c40f9bd5 --- /dev/null +++ b/framework/src/maven/apache-maven-3.3.3/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java @@ -0,0 +1,504 @@ +package org.apache.maven.model.interpolation; + +/* + * 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.maven.model.Model; +import org.apache.maven.model.building.ModelBuildingRequest; +import org.apache.maven.model.building.ModelProblem.Severity; +import org.apache.maven.model.building.ModelProblem.Version; +import org.apache.maven.model.building.ModelProblemCollector; +import org.apache.maven.model.building.ModelProblemCollectorRequest; +import org.codehaus.plexus.component.annotations.Component; +import org.codehaus.plexus.interpolation.InterpolationPostProcessor; +import org.codehaus.plexus.interpolation.Interpolator; +import org.codehaus.plexus.interpolation.StringSearchInterpolator; +import org.codehaus.plexus.interpolation.ValueSource; + +import java.io.File; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component( role = ModelInterpolator.class ) +public class StringSearchModelInterpolator + extends AbstractStringBasedModelInterpolator +{ + + private static final Map<Class<?>, InterpolateObjectAction.CacheItem> CACHED_ENTRIES = + new ConcurrentHashMap<Class<?>, InterpolateObjectAction.CacheItem>( 80, 0.75f, 2 ); + // Empirical data from 3.x, actual =40 + + + @Override + public Model interpolateModel( Model model, File projectDir, ModelBuildingRequest config, + ModelProblemCollector problems ) + { + interpolateObject( model, model, projectDir, config, problems ); + + return model; + } + + protected void interpolateObject( Object obj, Model model, File projectDir, ModelBuildingRequest config, + ModelProblemCollector problems ) + { + try + { + List<? extends ValueSource> valueSources = createValueSources( model, projectDir, config, problems ); + List<? extends InterpolationPostProcessor> postProcessors = + createPostProcessors( model, projectDir, config ); + + InterpolateObjectAction action = + new InterpolateObjectAction( obj, valueSources, postProcessors, this, problems ); + + AccessController.doPrivileged( action ); + } + finally + { + getInterpolator().clearAnswers(); + } + } + + @Override + protected Interpolator createInterpolator() + { + StringSearchInterpolator interpolator = new StringSearchInterpolator(); + interpolator.setCacheAnswers( true ); + + return interpolator; + } + + private static final class InterpolateObjectAction + implements PrivilegedAction<Object> + { + + private final LinkedList<Object> interpolationTargets; + + private final StringSearchModelInterpolator modelInterpolator; + + private final List<? extends ValueSource> valueSources; + + private final List<? extends InterpolationPostProcessor> postProcessors; + + private final ModelProblemCollector problems; + + public InterpolateObjectAction( Object target, List<? extends ValueSource> valueSources, + List<? extends InterpolationPostProcessor> postProcessors, + StringSearchModelInterpolator modelInterpolator, + ModelProblemCollector problems ) + { + this.valueSources = valueSources; + this.postProcessors = postProcessors; + + this.interpolationTargets = new LinkedList<Object>(); + interpolationTargets.add( target ); + + this.modelInterpolator = modelInterpolator; + + this.problems = problems; + } + + @Override + public Object run() + { + while ( !interpolationTargets.isEmpty() ) + { + Object obj = interpolationTargets.removeFirst(); + + traverseObjectWithParents( obj.getClass(), obj ); + } + + return null; + } + + + private String interpolate( String value ) + { + return modelInterpolator.interpolateInternal( value, valueSources, postProcessors, problems ); + } + + private void traverseObjectWithParents( Class<?> cls, Object target ) + { + if ( cls == null ) + { + return; + } + + CacheItem cacheEntry = getCacheEntry( cls ); + if ( cacheEntry.isArray() ) + { + evaluateArray( target, this ); + } + else if ( cacheEntry.isQualifiedForInterpolation ) + { + cacheEntry.interpolate( target, this ); + + traverseObjectWithParents( cls.getSuperclass(), target ); + } + } + + + private CacheItem getCacheEntry( Class<?> cls ) + { + CacheItem cacheItem = CACHED_ENTRIES.get( cls ); + if ( cacheItem == null ) + { + cacheItem = new CacheItem( cls ); + CACHED_ENTRIES.put( cls, cacheItem ); + } + return cacheItem; + } + + private static void evaluateArray( Object target, InterpolateObjectAction ctx ) + { + int len = Array.getLength( target ); + for ( int i = 0; i < len; i++ ) + { + Object value = Array.get( target, i ); + if ( value != null ) + { + if ( String.class == value.getClass() ) + { + String interpolated = ctx.interpolate( (String) value ); + + if ( !interpolated.equals( value ) ) + { + Array.set( target, i, interpolated ); + } + } + else + { + ctx.interpolationTargets.add( value ); + } + } + } + } + + private static class CacheItem + { + private final boolean isArray; + + private final boolean isQualifiedForInterpolation; + + private final CacheField[] fields; + + private boolean isQualifiedForInterpolation( Class<?> cls ) + { + return !cls.getName().startsWith( "java" ); + } + + private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType ) + { + if ( Map.class.equals( fieldType ) && "locations".equals( field.getName() ) ) + { + return false; + } + + //noinspection SimplifiableIfStatement + if ( fieldType.isPrimitive() ) + { + return false; + } + + return !"parent".equals( field.getName() ); + } + + CacheItem( Class clazz ) + { + this.isQualifiedForInterpolation = isQualifiedForInterpolation( clazz ); + this.isArray = clazz.isArray(); + List<CacheField> fields = new ArrayList<CacheField>(); + for ( Field currentField : clazz.getDeclaredFields() ) + { + Class<?> type = currentField.getType(); + if ( isQualifiedForInterpolation( currentField, type ) ) + { + if ( String.class == type ) + { + if ( !Modifier.isFinal( currentField.getModifiers() ) ) + { + fields.add( new StringField( currentField ) ); + } + } + else if ( List.class.isAssignableFrom( type ) ) + { + fields.add( new ListField( currentField ) ); + } + else if ( Collection.class.isAssignableFrom( type ) ) + { + throw new RuntimeException( "We dont interpolate into collections, use a list instead" ); + } + else if ( Map.class.isAssignableFrom( type ) ) + { + fields.add( new MapField( currentField ) ); + } + else + { + fields.add( new ObjectField( currentField ) ); + } + } + + } + this.fields = fields.toArray( new CacheField[fields.size()] ); + + } + + public void interpolate( Object target, InterpolateObjectAction interpolateObjectAction ) + { + for ( CacheField field : fields ) + { + field.interpolate( target, interpolateObjectAction ); + } + } + + public boolean isArray() + { + return isArray; + } + } + + abstract static class CacheField + { + protected final Field field; + + CacheField( Field field ) + { + this.field = field; + } + + void interpolate( Object target, InterpolateObjectAction interpolateObjectAction ) + { + synchronized ( field ) + { + boolean isAccessible = field.isAccessible(); + field.setAccessible( true ); + try + { + doInterpolate( target, interpolateObjectAction ); + } + catch ( IllegalArgumentException e ) + { + interpolateObjectAction.problems.add( + new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( + "Failed to interpolate field3: " + field + " on class: " + + field.getType().getName() ).setException( + e ) ); // todo: Not entirely the same message + } + catch ( IllegalAccessException e ) + { + interpolateObjectAction.problems.add( + new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( + "Failed to interpolate field4: " + field + " on class: " + + field.getType().getName() ).setException( e ) ); + } + finally + { + field.setAccessible( isAccessible ); + } + } + + + } + + abstract void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException; + } + + static final class StringField + extends CacheField + { + StringField( Field field ) + { + super( field ); + } + + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException + { + String value = (String) field.get( target ); + if ( value == null ) + { + return; + } + + String interpolated = ctx.interpolate( value ); + + if ( !interpolated.equals( value ) ) + { + field.set( target, interpolated ); + } + } + } + + static final class ListField + extends CacheField + { + ListField( Field field ) + { + super( field ); + } + + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException + { + @SuppressWarnings( "unchecked" ) List<Object> c = (List<Object>) field.get( target ); + if ( c == null ) + { + return; + } + + int size = c.size(); + Object value; + for ( int i = 0; i < size; i++ ) + { + + value = c.get( i ); + + if ( value != null ) + { + if ( String.class == value.getClass() ) + { + String interpolated = ctx.interpolate( (String) value ); + + if ( !interpolated.equals( value ) ) + { + try + { + c.set( i, interpolated ); + } + catch ( UnsupportedOperationException e ) + { + return; + } + } + } + else + { + if ( value.getClass().isArray() ) + { + evaluateArray( value, ctx ); + } + else + { + ctx.interpolationTargets.add( value ); + } + } + } + } + } + } + + static final class MapField + extends CacheField + { + MapField( Field field ) + { + super( field ); + } + + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException + { + @SuppressWarnings( "unchecked" ) Map<Object, Object> m = (Map<Object, Object>) field.get( target ); + if ( m == null || m.isEmpty() ) + { + return; + } + + for ( Map.Entry<Object, Object> entry : m.entrySet() ) + { + Object value = entry.getValue(); + + if ( value == null ) + { + continue; + } + + if ( String.class == value.getClass() ) + { + String interpolated = ctx.interpolate( (String) value ); + + if ( !interpolated.equals( value ) ) + { + try + { + entry.setValue( interpolated ); + } + catch ( UnsupportedOperationException ignore ) + { + // nop + } + } + } + else if ( value.getClass().isArray() ) + { + evaluateArray( value, ctx ); + } + else + { + ctx.interpolationTargets.add( value ); + } + } + } + } + + static final class ObjectField + extends CacheField + { + private final boolean isArray; + + ObjectField( Field field ) + { + super( field ); + this.isArray = field.getType().isArray(); + } + + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException + { + Object value = field.get( target ); + if ( value != null ) + { + if ( isArray ) + { + evaluateArray( value, ctx ); + } + else + { + ctx.interpolationTargets.add( value ); + } + } + } + } + + } + +} |