View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.configuration.internal;
20  
21  import javax.inject.Named;
22  import javax.inject.Singleton;
23  
24  import java.io.File;
25  import java.nio.file.Path;
26  import java.nio.file.Paths;
27  import java.util.Objects;
28  
29  import org.apache.maven.configuration.BeanConfigurationException;
30  import org.apache.maven.configuration.BeanConfigurationPathTranslator;
31  import org.apache.maven.configuration.BeanConfigurationRequest;
32  import org.apache.maven.configuration.BeanConfigurationValuePreprocessor;
33  import org.apache.maven.configuration.BeanConfigurator;
34  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
35  import org.codehaus.plexus.component.configurator.ConfigurationListener;
36  import org.codehaus.plexus.component.configurator.converters.basic.AbstractBasicConverter;
37  import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter;
38  import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
39  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
40  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
41  import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
42  import org.codehaus.plexus.configuration.PlexusConfiguration;
43  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
44  import org.codehaus.plexus.util.xml.Xpp3Dom;
45  
46  /**
47   * <strong>Warning:</strong> This is an internal class that is only public for technical reasons, it is not part of the
48   * public API. In particular, this class can be changed or deleted without prior notice.
49   *
50   * @author Benjamin Bentmann
51   */
52  @Named
53  @Singleton
54  public class DefaultBeanConfigurator implements BeanConfigurator {
55  
56      private final ConverterLookup converterLookup;
57  
58      public DefaultBeanConfigurator() {
59          converterLookup = new EnhancedConverterLookup();
60      }
61  
62      public void configureBean(BeanConfigurationRequest request) throws BeanConfigurationException {
63          Objects.requireNonNull(request, "request cannot be null");
64          Objects.requireNonNull(request.getBean(), "request.bean cannot be null");
65  
66          Object configuration = request.getConfiguration();
67          if (configuration == null) {
68              return;
69          }
70  
71          PlexusConfiguration plexusConfig;
72          if (configuration instanceof PlexusConfiguration) {
73              plexusConfig = (PlexusConfiguration) configuration;
74          } else if (configuration instanceof Xpp3Dom) {
75              plexusConfig = new XmlPlexusConfiguration((Xpp3Dom) configuration);
76          } else {
77              throw new BeanConfigurationException("unsupported bean configuration source ("
78                      + configuration.getClass().getName() + ")");
79          }
80  
81          if (request.getConfigurationElement() != null) {
82              plexusConfig = plexusConfig.getChild(request.getConfigurationElement());
83          }
84  
85          ClassLoader classLoader = request.getClassLoader();
86          if (classLoader == null) {
87              classLoader = request.getBean().getClass().getClassLoader();
88          }
89  
90          BeanExpressionEvaluator evaluator = new BeanExpressionEvaluator(request);
91  
92          ObjectWithFieldsConverter converter = new EnhancedConfigurationConverter();
93  
94          try {
95              converter.processConfiguration(
96                      converterLookup, request.getBean(), classLoader, plexusConfig, evaluator, null);
97          } catch (ComponentConfigurationException e) {
98              throw new BeanConfigurationException(e.getMessage(), e);
99          }
100     }
101 
102     static class BeanExpressionEvaluator implements TypeAwareExpressionEvaluator {
103 
104         private final BeanConfigurationValuePreprocessor preprocessor;
105 
106         private final BeanConfigurationPathTranslator translator;
107 
108         BeanExpressionEvaluator(BeanConfigurationRequest request) {
109             preprocessor = request.getValuePreprocessor();
110             translator = request.getPathTranslator();
111         }
112 
113         public Object evaluate(String expression, Class<?> type) throws ExpressionEvaluationException {
114             if (preprocessor != null) {
115                 try {
116                     return preprocessor.preprocessValue(expression, type);
117                 } catch (BeanConfigurationException e) {
118                     throw new ExpressionEvaluationException(e.getMessage(), e);
119                 }
120             }
121             return expression;
122         }
123 
124         public Object evaluate(String expression) throws ExpressionEvaluationException {
125             return evaluate(expression, null);
126         }
127 
128         public File alignToBaseDirectory(File file) {
129             if (translator != null) {
130                 return translator.translatePath(file);
131             }
132             return file;
133         }
134     }
135 
136     static class PathConverter extends AbstractBasicConverter {
137         @Override
138         public boolean canConvert(Class<?> type) {
139             return Path.class.equals(type);
140         }
141 
142         @Override
143         protected Object fromString(String value) throws ComponentConfigurationException {
144             return Paths.get(value.replace('/' == File.separatorChar ? '\\' : '/', File.separatorChar));
145         }
146 
147         @Override
148         public Object fromConfiguration(
149                 final ConverterLookup lookup,
150                 final PlexusConfiguration configuration,
151                 final Class<?> type,
152                 final Class<?> enclosingType,
153                 final ClassLoader loader,
154                 final ExpressionEvaluator evaluator,
155                 final ConfigurationListener listener)
156                 throws ComponentConfigurationException {
157             final Object result =
158                     super.fromConfiguration(lookup, configuration, type, enclosingType, loader, evaluator, listener);
159 
160             return result instanceof Path
161                     ? evaluator.alignToBaseDirectory(((Path) result).toFile()).toPath()
162                     : result;
163         }
164     }
165 }