Java tutorial
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.InputLocation; 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.interpolation.InterpolationException; import org.codehaus.plexus.interpolation.InterpolationPostProcessor; import org.codehaus.plexus.interpolation.RecursionInterceptor; 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.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * StringSearchModelInterpolator * @deprecated replaced by StringVisitorModelInterpolator (MNG-6697) */ @Deprecated public class StringSearchModelInterpolator extends AbstractStringBasedModelInterpolator { private static final Map<Class<?>, InterpolateObjectAction.CacheItem> CACHED_ENTRIES = new ConcurrentHashMap<>( 80, 0.75f, 2); // Empirical data from 3.x, actual =40 private interface InnerInterpolator { String interpolate(String value); } @Override public Model interpolateModel(Model model, File projectDir, ModelBuildingRequest config, ModelProblemCollector problems) { interpolateObject(model, model, projectDir, config, problems); return model; } void interpolateObject(Object obj, Model model, File projectDir, ModelBuildingRequest config, ModelProblemCollector problems) { List<? extends ValueSource> valueSources = createValueSources(model, projectDir, config, problems); List<? extends InterpolationPostProcessor> postProcessors = createPostProcessors(model, projectDir, config); InnerInterpolator innerInterpolator = createInterpolator(valueSources, postProcessors, problems); PrivilegedAction<Object> action = new InterpolateObjectAction(obj, innerInterpolator, problems); AccessController.doPrivileged(action); } private InnerInterpolator createInterpolator(List<? extends ValueSource> valueSources, List<? extends InterpolationPostProcessor> postProcessors, final ModelProblemCollector problems) { final Map<String, String> cache = new HashMap<>(); final StringSearchInterpolator interpolator = new StringSearchInterpolator(); interpolator.setCacheAnswers(true); for (ValueSource vs : valueSources) { interpolator.addValueSource(vs); } for (InterpolationPostProcessor postProcessor : postProcessors) { interpolator.addPostProcessor(postProcessor); } final RecursionInterceptor recursionInterceptor = createRecursionInterceptor(); return new InnerInterpolator() { @Override public String interpolate(String value) { if (value != null && value.contains("${")) { String c = cache.get(value); if (c == null) { try { c = interpolator.interpolate(value, recursionInterceptor); } catch (InterpolationException e) { problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE) .setMessage(e.getMessage()).setException(e)); } cache.put(value, c); } return c; } return value; } }; } private static final class InterpolateObjectAction implements PrivilegedAction<Object> { private final LinkedList<Object> interpolationTargets; private final InnerInterpolator interpolator; private final ModelProblemCollector problems; InterpolateObjectAction(Object target, InnerInterpolator interpolator, ModelProblemCollector problems) { this.interpolationTargets = new LinkedList<>(); interpolationTargets.add(target); this.interpolator = interpolator; 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 interpolator.interpolate(value); } 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) { Package pkg = cls.getPackage(); if (pkg == null) { return true; } String pkgName = pkg.getName(); return !pkgName.startsWith("java.") && !pkgName.startsWith("javax."); } private boolean isQualifiedForInterpolation(Field field, Class<?> fieldType) { if (Map.class.equals(fieldType) && "locations".equals(field.getName())) { return false; } if (InputLocation.class.equals(fieldType)) { 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<>(); if (isQualifiedForInterpolation) { 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[0]); } void interpolate(Object target, InterpolateObjectAction interpolateObjectAction) { for (CacheField field : fields) { field.interpolate(target, interpolateObjectAction); } } boolean isArray() { return isArray; } } abstract static class CacheField { final Field field; CacheField(Field field) { this.field = field; field.setAccessible(true); } void interpolate(Object target, InterpolateObjectAction interpolateObjectAction) { 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)); } } 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; } for (int i = 0, size = c.size(); i < size; i++) { Object 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); } } } } } }