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 java.io.File;
22  import java.nio.file.Path;
23  import java.nio.file.Paths;
24  import java.util.Objects;
25  import javax.inject.Named;
26  import javax.inject.Singleton;
27  import org.apache.maven.configuration.BeanConfigurationException;
28  import org.apache.maven.configuration.BeanConfigurationPathTranslator;
29  import org.apache.maven.configuration.BeanConfigurationRequest;
30  import org.apache.maven.configuration.BeanConfigurationValuePreprocessor;
31  import org.apache.maven.configuration.BeanConfigurator;
32  import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
33  import org.codehaus.plexus.component.configurator.ConfigurationListener;
34  import org.codehaus.plexus.component.configurator.converters.basic.AbstractBasicConverter;
35  import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter;
36  import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
37  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
38  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
39  import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
40  import org.codehaus.plexus.configuration.PlexusConfiguration;
41  import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
42  import org.codehaus.plexus.util.xml.Xpp3Dom;
43  
44  /**
45   * <strong>Warning:</strong> This is an internal class that is only public for technical reasons, it is not part of the
46   * public API. In particular, this class can be changed or deleted without prior notice.
47   *
48   * @author Benjamin Bentmann
49   */
50  @Named
51  @Singleton
52  public class DefaultBeanConfigurator implements BeanConfigurator {
53  
54      private final ConverterLookup converterLookup;
55  
56      public DefaultBeanConfigurator() {
57          converterLookup = new EnhancedConverterLookup();
58      }
59  
60      public void configureBean(BeanConfigurationRequest request) throws BeanConfigurationException {
61          Objects.requireNonNull(request, "request cannot be null");
62          Objects.requireNonNull(request.getBean(), "request.bean cannot be null");
63  
64          Object configuration = request.getConfiguration();
65          if (configuration == null) {
66              return;
67          }
68  
69          PlexusConfiguration plexusConfig;
70          if (configuration instanceof PlexusConfiguration) {
71              plexusConfig = (PlexusConfiguration) configuration;
72          } else if (configuration instanceof Xpp3Dom) {
73              plexusConfig = new XmlPlexusConfiguration((Xpp3Dom) configuration);
74          } else {
75              throw new BeanConfigurationException("unsupported bean configuration source ("
76                      + configuration.getClass().getName() + ")");
77          }
78  
79          if (request.getConfigurationElement() != null) {
80              plexusConfig = plexusConfig.getChild(request.getConfigurationElement());
81          }
82  
83          ClassLoader classLoader = request.getClassLoader();
84          if (classLoader == null) {
85              classLoader = request.getBean().getClass().getClassLoader();
86          }
87  
88          BeanExpressionEvaluator evaluator = new BeanExpressionEvaluator(request);
89  
90          ObjectWithFieldsConverter converter = new EnhancedConfigurationConverter();
91  
92          try {
93              converter.processConfiguration(
94                      converterLookup, request.getBean(), classLoader, plexusConfig, evaluator, null);
95          } catch (ComponentConfigurationException e) {
96              throw new BeanConfigurationException(e.getMessage(), e);
97          }
98      }
99  
100     static class BeanExpressionEvaluator implements TypeAwareExpressionEvaluator {
101 
102         private final BeanConfigurationValuePreprocessor preprocessor;
103 
104         private final BeanConfigurationPathTranslator translator;
105 
106         BeanExpressionEvaluator(BeanConfigurationRequest request) {
107             preprocessor = request.getValuePreprocessor();
108             translator = request.getPathTranslator();
109         }
110 
111         public Object evaluate(String expression, Class<?> type) throws ExpressionEvaluationException {
112             if (preprocessor != null) {
113                 try {
114                     return preprocessor.preprocessValue(expression, type);
115                 } catch (BeanConfigurationException e) {
116                     throw new ExpressionEvaluationException(e.getMessage(), e);
117                 }
118             }
119             return expression;
120         }
121 
122         public Object evaluate(String expression) throws ExpressionEvaluationException {
123             return evaluate(expression, null);
124         }
125 
126         public File alignToBaseDirectory(File file) {
127             if (translator != null) {
128                 return translator.translatePath(file);
129             }
130             return file;
131         }
132     }
133 
134     static class PathConverter extends AbstractBasicConverter {
135         @Override
136         public boolean canConvert(Class<?> type) {
137             return Path.class.equals(type);
138         }
139 
140         @Override
141         protected Object fromString(String value) throws ComponentConfigurationException {
142             return Paths.get(value.replace('/' == File.separatorChar ? '\\' : '/', File.separatorChar));
143         }
144 
145         @Override
146         public Object fromConfiguration(
147                 final ConverterLookup lookup,
148                 final PlexusConfiguration configuration,
149                 final Class<?> type,
150                 final Class<?> enclosingType,
151                 final ClassLoader loader,
152                 final ExpressionEvaluator evaluator,
153                 final ConfigurationListener listener)
154                 throws ComponentConfigurationException {
155             final Object result =
156                     super.fromConfiguration(lookup, configuration, type, enclosingType, loader, evaluator, listener);
157 
158             return result instanceof Path
159                     ? evaluator.alignToBaseDirectory(((Path) result).toFile()).toPath()
160                     : result;
161         }
162     }
163 }