File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\maven-plugin\src\main\java\hudson\maven\MojoInfo.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.maven;
25
26 import org.apache.maven.execution.ExecutionEvent;
27 import org.apache.maven.plugin.AbstractMojo;
28 import org.apache.maven.plugin.MojoExecution;
29 import org.apache.maven.plugin.Mojo;
30 import org.apache.maven.plugin.MojoExecutionException;
31 import org.apache.maven.plugin.MojoFailureException;
32 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
33 import org.apache.maven.plugin.descriptor.PluginDescriptor;
34 import org.codehaus.classworlds.ClassRealm;
35 import org.codehaus.plexus.configuration.PlexusConfiguration;
36 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
37 import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
38 import org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup;
39 import org.codehaus.plexus.component.configurator.converters.ConfigurationConverter;
40 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
41
42 import java.io.File;
43 import java.lang.reflect.Field;
44 import java.lang.reflect.InvocationHandler;
45 import java.lang.reflect.Proxy;
46 import java.lang.reflect.Method;
47
48 import javax.annotation.CheckForNull;
49
50 import hudson.util.InvocationInterceptor;
51 import hudson.util.ReflectionUtils;
52 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
53
54 /**
55 * Information about Mojo to be executed. This object provides
56 * convenient access to various mojo information, so that {@link MavenReporter}
57 * implementations are shielded to some extent from Maven internals.
58 *
59 * <p>
60 * For each mojo to be executed, this object is created and passed to
61 * {@link MavenReporter}.
62 *
63 * @author Kohsuke Kawaguchi
64 * @see MavenReporter
65 * @see MavenReportInfo
66 */
67 public class MojoInfo {
68 /**
69 * Object from Maven that describes the Mojo to be executed.
70 */
71 public final MojoExecution mojoExecution;
72
73 /**
74 * PluginName of the plugin that contains this mojo.
75 */
76 public final PluginName pluginName;
77
78 /**
79 * Mojo object that carries out the actual execution.
80 *
81 * @deprecated as of 1.427
82 * Maven3 can no longer provide this information, so plugins cannot rely on this value being present.
83 * For the time being we are setting a dummy value to avoid NPE. Use {@link #configuration} to access
84 * configuration values, but otherwise the ability to inject values is lost and there's no viable
85 * alternative.
86 */
87 public final Mojo mojo;
88
89 /**
90 * Configuration of the mojo for the current execution.
91 * This reflects the default values, as well as values configured from POM,
92 * including inherited values.
93 */
94 public final PlexusConfiguration configuration;
95
96 /**
97 * Object that Maven uses to resolve variables like "${project}" to its
98 * corresponding object.
99 */
100 public final ExpressionEvaluator expressionEvaluator;
101
102 /**
103 * Used to obtain a value from {@link PlexusConfiguration} as a typed object,
104 * instead of String.
105 */
106 private final ConverterLookup converterLookup = new DefaultConverterLookup();
107
108 private long startTime;
109
110 public MojoInfo(MojoExecution mojoExecution, Mojo mojo, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator,
111 long startTime) {
112 // in Maven3 there's no easy way to get the Mojo instance that's being executed,
113 // so we just can't pass it in.
114 if (mojo==null) mojo = new Maven3ProvidesNoAccessToMojo();
115 this.mojo = mojo;
116 this.mojoExecution = mojoExecution;
117 this.configuration = configuration;
118 this.expressionEvaluator = expressionEvaluator;
119 this.pluginName = new PluginName(mojoExecution.getMojoDescriptor().getPluginDescriptor());
120 this.startTime = startTime;
121 }
122
123 public MojoInfo(ExecutionEvent event, long startTime) {
124 this(event.getMojoExecution(), null,
125 new XmlPlexusConfiguration( event.getMojoExecution().getConfiguration() ),
126 new PluginParameterExpressionEvaluator( event.getSession(), event.getMojoExecution() ), startTime);
127 }
128
129 /**
130 * Gets the goal name of the mojo to be executed,
131 * such as "javadoc". This is local to the plugin name.
132 */
133 public String getGoal() {
134 return mojoExecution.getMojoDescriptor().getGoal();
135 }
136
137 /**
138 * Obtains the configuration value of the mojo.
139 *
140 * @param configName
141 * The name of the child element in the &lt;configuration> of mojo.
142 * @param type
143 * The Java class of the configuration value. While every element
144 * can be read as {@link String}, often different types have a different
145 * conversion rules associated with it (for example, {@link File} would
146 * resolve relative path against POM base directory.)
147 * @param defaultValue
148 * The default value to return in case the mojo doesn't have such
149 * configuration value
150 *
151 * @return
152 * The configuration value either specified in POM, or inherited from
153 * parent POM, or default value if one is specified in mojo,
154 * or the defaultValue parameter if no such configuration value exists.
155 *
156 * @throws ComponentConfigurationException
157 * Not sure when exactly this is thrown, but it's probably when
158 * the configuration in POM is syntactically incorrect.
159 */
160 public <T> T getConfigurationValue(String configName, Class<T> type, T defaultValue) throws ComponentConfigurationException {
161 T value = getConfigurationValue(configName, type);
162 return value != null ? value : defaultValue;
163 }
164
165 /**
166 * Obtains the configuration value of the mojo.
167 *
168 * @param configName
169 * The name of the child element in the &lt;configuration> of mojo.
170 * @param type
171 * The Java class of the configuration value. While every element
172 * can be read as {@link String}, often different types have a different
173 * conversion rules associated with it (for example, {@link File} would
174 * resolve relative path against POM base directory.)
175 *
176 * @return
177 * The configuration value either specified in POM, or inherited from
178 * parent POM, or default value if one is specified in mojo,
179 * or null if no such configuration value exists.
180 *
181 * @throws ComponentConfigurationException
182 * Not sure when exactly this is thrown, but it's probably when
183 * the configuration in POM is syntactically incorrect.
184 */
185 @CheckForNull public <T> T getConfigurationValue(String configName, Class<T> type) throws ComponentConfigurationException {
186 PlexusConfiguration child = configuration.getChild(configName,false);
187 if(child==null) return null; // no such config
188
189 final ClassLoader cl;
190 PluginDescriptor pd = mojoExecution.getMojoDescriptor().getPluginDescriptor();
191
192 // For maven2 builds getClassRealm returns a org.codehaus.classworlds.ClassRealm (instead of
193 // org.codehaus.plexus.classworlds.realm.ClassRealm)
194 // which doesn't extends ClassLoader !
195 // So get this with reflection and access the nested classloader ("getClassLoader")
196 Method method = ReflectionUtils.getPublicMethodNamed( pd.getClass(), "getClassRealm" );
197
198 Object classRealm = ReflectionUtils.invokeMethod( method, pd );
199 if ( classRealm instanceof ClassRealm) {
200 ClassRealm cr = (ClassRealm) classRealm;
201 cl = cr.getClassLoader();
202 } else {
203 cl = mojoExecution.getMojoDescriptor().getPluginDescriptor().getClassRealm();
204 }
205 ConfigurationConverter converter = converterLookup.lookupConverterForType(type);
206 return type.cast(converter.fromConfiguration(converterLookup,child,type,
207 // the implementation seems to expect the type of the bean for which the configuration is done
208 // in this parameter, but we have no such type. So passing in a dummy
209 Object.class,
210 cl,
211 expressionEvaluator));
212 }
213
214 /**
215 * Returns true if this {@link MojoInfo} wraps the mojo of the given ID tuple.
216 */
217 public boolean is(String groupId, String artifactId, String mojoName) {
218 return pluginName.matches(groupId,artifactId) && getGoal().equals(mojoName);
219 }
220
221 /**
222 * Injects the specified value (designated by the specified field name) into the mojo,
223 * and returns its old value.
224 *
225 * @throws NoSuchFieldException
226 * if the mojo doesn't have any field of the given name.
227 * @since 1.232
228 * @deprecated as of 1.427
229 * See the discussion in {@link #mojo}
230 */
231 @SuppressWarnings("unchecked")
232 public <T> T inject(String name, T value) throws NoSuchFieldException {
233 for(Class<?> c=mojo.getClass(); c!=Object.class; c=c.getSuperclass()) {
234 try {
235 Field f = c.getDeclaredField(name);
236 f.setAccessible(true);
237 Object oldValue = f.get(mojo);
238 f.set(mojo,value);
239 return (T)oldValue;
240 } catch (NoSuchFieldException e) {
241 continue;
242 } catch (IllegalAccessException e) {
243 // shouldn't happen because we made it accessible
244 IllegalAccessError x = new IllegalAccessError(e.getMessage());
245 x.initCause(e);
246 throw x;
247 }
248 }
249
250 throw new NoSuchFieldException(name);
251 }
252
253 /**
254 * Intercept the invocation from the mojo to its injected component (designated by the given field name.)
255 *
256 * <p>
257 * Often for a {@link MavenReporter} to really figure out what's going on in a build, you'd like
258 * to intercept one of the components that Maven is injecting into the mojo, and inspect its parameter
259 * and return values.
260 *
261 * <p>
262 * This mehod provides a way to do this. You specify the name of the field in the Mojo class that receives
263 * the injected component, then pass in {@link InvocationInterceptor}, which will in turn be invoked
264 * for every invocation on that component.
265 *
266 * @throws NoSuchFieldException
267 * if the specified field is not found on the mojo class, or it is found but the type is not an interface.
268 * @since 1.232
269 * @deprecated as of 1.427
270 * See the discussion in {@link #mojo}
271 */
272 public void intercept(String fieldName, final InvocationInterceptor interceptor) throws NoSuchFieldException {
273 for(Class<?> c=mojo.getClass(); c!=Object.class; c=c.getSuperclass()) {
274 Field f;
275 try {
276 f = c.getDeclaredField(fieldName);
277 } catch (NoSuchFieldException e) {
278 continue;
279 }
280
281 f.setAccessible(true);
282 Class<?> type = f.getType();
283 if(!type.isInterface())
284 throw new NoSuchFieldException(fieldName+" is of type "+type+" and it's not an interface");
285
286 try {
287 final Object oldObject = f.get(mojo);
288
289 Object newObject = Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, new InvocationHandler() {
290 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
291 return interceptor.invoke(proxy,method,args,new InvocationHandler() {
292 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
293 return method.invoke(oldObject,args);
294 }
295 });
296 }
297 });
298
299 f.set(mojo,newObject);
300 } catch (IllegalAccessException e) {
301 // shouldn't happen because we made it accessible
302 IllegalAccessError x = new IllegalAccessError(e.getMessage());
303 x.initCause(e);
304 throw x;
305 }
306 }
307 }
308
309 /**
310 * Instance will be set to {@link MojoInfo#mojo} to avoid NPE in plugins.
311 */
312 public static class Maven3ProvidesNoAccessToMojo extends AbstractMojo {
313 public void execute() throws MojoExecutionException, MojoFailureException {
314 throw new UnsupportedOperationException();
315 }
316 }
317
318 public long getStartTime() {
319 return this.startTime;
320 }
321 }
322