Java tutorial
package org.apache.maven.plugin.testing; /* * 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 java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.Reader; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.apache.commons.io.input.XmlStreamReader; import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.DefaultMavenExecutionRequest; import org.apache.maven.execution.DefaultMavenExecutionResult; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionResult; import org.apache.maven.execution.MavenSession; import org.apache.maven.lifecycle.internal.MojoDescriptorCreator; import org.apache.maven.model.Plugin; import org.apache.maven.monitor.logging.DefaultLog; import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.PluginParameterExpressionEvaluator; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.Parameter; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder; import org.apache.maven.plugin.logging.Log; import org.apache.maven.project.MavenProject; import org.apache.maven.repository.RepositorySystem; import org.apache.maven.repository.internal.MavenAetherModule; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; import org.codehaus.plexus.ContainerConfiguration; import org.codehaus.plexus.DefaultContainerConfiguration; import org.codehaus.plexus.DefaultPlexusContainer; import org.codehaus.plexus.PlexusConstants; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.PlexusContainerException; import org.codehaus.plexus.PlexusTestCase; import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.component.configurator.ComponentConfigurationException; import org.codehaus.plexus.component.configurator.ComponentConfigurator; import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator; import org.codehaus.plexus.component.repository.ComponentDescriptor; import org.codehaus.plexus.configuration.PlexusConfiguration; import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration; import org.codehaus.plexus.logging.LoggerManager; import org.codehaus.plexus.util.InterpolationFilterReader; import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.ReflectionUtils; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.codehaus.plexus.util.xml.Xpp3DomBuilder; /** * TODO: add a way to use the plugin POM for the lookup so that the user doesn't have to provide the a:g:v:goal * as the role hint for the mojo lookup. * TODO: standardize the execution of the mojo and looking at the results, but could simply have a template method * for verifying the state of the mojo post execution * TODO: need a way to look at the state of the mojo without adding getters, this could be where we finally specify * the expressions which extract values from the mojo. * TODO: create a standard directory structure for picking up POMs to make this even easier, we really just need a testing * descriptor and make this entirely declarative! * * @author jesse * @version $Id: AbstractMojoTestCase.java 1505991 2013-07-23 11:49:59Z jvanzyl $ */ public abstract class AbstractMojoTestCase extends PlexusTestCase { private ComponentConfigurator configurator; private PlexusContainer container; private Map<String, MojoDescriptor> mojoDescriptors; /* * for the harness I think we have decided against going the route of using the maven project builder. * instead I think we are going to try and make an instance of the localrespository and assign that * to either the project stub or into the mojo directly with injection...not sure yet though. */ //private MavenProjectBuilder projectBuilder; protected void setUp() throws Exception { configurator = getContainer().lookup(ComponentConfigurator.class, "basic"); InputStream is = getClass().getResourceAsStream("/" + getPluginDescriptorLocation()); XmlStreamReader reader = new XmlStreamReader(is); InterpolationFilterReader interpolationFilterReader = new InterpolationFilterReader( new BufferedReader(reader), container.getContext().getContextData()); PluginDescriptor pluginDescriptor = new PluginDescriptorBuilder().build(interpolationFilterReader); Artifact artifact = lookup(RepositorySystem.class).createArtifact(pluginDescriptor.getGroupId(), pluginDescriptor.getArtifactId(), pluginDescriptor.getVersion(), ".jar"); artifact.setFile(new File(getBasedir()).getCanonicalFile()); pluginDescriptor.setPluginArtifact(artifact); pluginDescriptor.setArtifacts(Arrays.asList(artifact)); for (ComponentDescriptor<?> desc : pluginDescriptor.getComponents()) { getContainer().addComponentDescriptor(desc); } mojoDescriptors = new HashMap<String, MojoDescriptor>(); for (MojoDescriptor mojoDescriptor : pluginDescriptor.getMojos()) { mojoDescriptors.put(mojoDescriptor.getGoal(), mojoDescriptor); } } protected InputStream getPublicDescriptorStream() throws Exception { return new FileInputStream(new File(getPluginDescriptorPath())); } protected String getPluginDescriptorPath() { return getBasedir() + "/target/classes/META-INF/maven/plugin.xml"; } protected String getPluginDescriptorLocation() { return "META-INF/maven/plugin.xml"; } protected void setupContainer() { ContainerConfiguration cc = setupContainerConfiguration(); try { container = new DefaultPlexusContainer(cc); } catch (PlexusContainerException e) { e.printStackTrace(); fail("Failed to create plexus container."); } } protected ContainerConfiguration setupContainerConfiguration() { ClassWorld classWorld = new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader()); ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld(classWorld) .setClassPathScanning(PlexusConstants.SCANNING_INDEX).setAutoWiring(true).setName("maven"); return cc; } protected PlexusContainer getContainer() { if (container == null) { setupContainer(); } return container; } /** * Lookup the mojo leveraging the subproject pom * * @param goal * @param pluginPom * @return a Mojo instance * @throws Exception */ protected Mojo lookupMojo(String goal, String pluginPom) throws Exception { return lookupMojo(goal, new File(pluginPom)); } /** * Lookup an empty mojo * * @param goal * @param pluginPom * @return a Mojo instance * @throws Exception */ protected Mojo lookupEmptyMojo(String goal, String pluginPom) throws Exception { return lookupEmptyMojo(goal, new File(pluginPom)); } /** * Lookup the mojo leveraging the actual subprojects pom * * @param goal * @param pom * @return a Mojo instance * @throws Exception */ protected Mojo lookupMojo(String goal, File pom) throws Exception { File pluginPom = new File(getBasedir(), "pom.xml"); Xpp3Dom pluginPomDom = Xpp3DomBuilder.build(ReaderFactory.newXmlReader(pluginPom)); String artifactId = pluginPomDom.getChild("artifactId").getValue(); String groupId = resolveFromRootThenParent(pluginPomDom, "groupId"); String version = resolveFromRootThenParent(pluginPomDom, "version"); PlexusConfiguration pluginConfiguration = extractPluginConfiguration(artifactId, pom); return lookupMojo(groupId, artifactId, version, goal, pluginConfiguration); } /** * Lookup the mojo leveraging the actual subprojects pom * * @param goal * @param pom * @return a Mojo instance * @throws Exception */ protected Mojo lookupEmptyMojo(String goal, File pom) throws Exception { File pluginPom = new File(getBasedir(), "pom.xml"); Xpp3Dom pluginPomDom = Xpp3DomBuilder.build(ReaderFactory.newXmlReader(pluginPom)); String artifactId = pluginPomDom.getChild("artifactId").getValue(); String groupId = resolveFromRootThenParent(pluginPomDom, "groupId"); String version = resolveFromRootThenParent(pluginPomDom, "version"); return lookupMojo(groupId, artifactId, version, goal, null); } /* protected Mojo lookupMojo( String groupId, String artifactId, String version, String goal, File pom ) throws Exception { PlexusConfiguration pluginConfiguration = extractPluginConfiguration( artifactId, pom ); return lookupMojo( groupId, artifactId, version, goal, pluginConfiguration ); } */ /** * lookup the mojo while we have all of the relavent information * * @param groupId * @param artifactId * @param version * @param goal * @param pluginConfiguration * @return a Mojo instance * @throws Exception */ protected Mojo lookupMojo(String groupId, String artifactId, String version, String goal, PlexusConfiguration pluginConfiguration) throws Exception { validateContainerStatus(); // pluginkey = groupId : artifactId : version : goal Mojo mojo = (Mojo) lookup(Mojo.ROLE, groupId + ":" + artifactId + ":" + version + ":" + goal); LoggerManager loggerManager = (LoggerManager) getContainer().lookup(LoggerManager.class); Log mojoLogger = new DefaultLog(loggerManager.getLoggerForComponent(Mojo.ROLE)); mojo.setLog(mojoLogger); if (pluginConfiguration != null) { /* requires v10 of plexus container for lookup on expression evaluator ExpressionEvaluator evaluator = (ExpressionEvaluator) getContainer().lookup( ExpressionEvaluator.ROLE, "stub-evaluator" ); */ ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub(); configurator.configureComponent(mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm()); } return mojo; } /** * * @param project * @param goal * @return * @throws Exception * @since 2.0 */ protected Mojo lookupConfiguredMojo(MavenProject project, String goal) throws Exception { return lookupConfiguredMojo(newMavenSession(project), newMojoExecution(goal)); } /** * * @param session * @param execution * @return * @throws Exception * @throws ComponentConfigurationException * @since 2.0 */ protected Mojo lookupConfiguredMojo(MavenSession session, MojoExecution execution) throws Exception, ComponentConfigurationException { MavenProject project = session.getCurrentProject(); MojoDescriptor mojoDescriptor = execution.getMojoDescriptor(); Mojo mojo = (Mojo) lookup(mojoDescriptor.getRole(), mojoDescriptor.getRoleHint()); ExpressionEvaluator evaluator = new PluginParameterExpressionEvaluator(session, execution); Xpp3Dom configuration = null; Plugin plugin = project.getPlugin(mojoDescriptor.getPluginDescriptor().getPluginLookupKey()); if (plugin != null) { configuration = (Xpp3Dom) plugin.getConfiguration(); } if (configuration == null) { configuration = new Xpp3Dom("configuration"); } configuration = Xpp3Dom.mergeXpp3Dom(execution.getConfiguration(), configuration); PlexusConfiguration pluginConfiguration = new XmlPlexusConfiguration(configuration); configurator.configureComponent(mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm()); return mojo; } /** * * @param project * @return * @since 2.0 */ protected MavenSession newMavenSession(MavenProject project) { MavenExecutionRequest request = new DefaultMavenExecutionRequest(); MavenExecutionResult result = new DefaultMavenExecutionResult(); MavenSession session = new MavenSession(container, MavenRepositorySystemUtils.newSession(), request, result); session.setCurrentProject(project); session.setProjects(Arrays.asList(project)); return session; } /** * * @param goal * @return * @since 2.0 */ protected MojoExecution newMojoExecution(String goal) { MojoDescriptor mojoDescriptor = mojoDescriptors.get(goal); assertNotNull(mojoDescriptor); MojoExecution execution = new MojoExecution(mojoDescriptor); finalizeMojoConfiguration(execution); return execution; } // copy&paste from org.apache.maven.lifecycle.internal.DefaultLifecycleExecutionPlanCalculator.finalizeMojoConfiguration(MojoExecution) private void finalizeMojoConfiguration(MojoExecution mojoExecution) { MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor(); Xpp3Dom executionConfiguration = mojoExecution.getConfiguration(); if (executionConfiguration == null) { executionConfiguration = new Xpp3Dom("configuration"); } Xpp3Dom defaultConfiguration = MojoDescriptorCreator.convert(mojoDescriptor); ; Xpp3Dom finalConfiguration = new Xpp3Dom("configuration"); if (mojoDescriptor.getParameters() != null) { for (Parameter parameter : mojoDescriptor.getParameters()) { Xpp3Dom parameterConfiguration = executionConfiguration.getChild(parameter.getName()); if (parameterConfiguration == null) { parameterConfiguration = executionConfiguration.getChild(parameter.getAlias()); } Xpp3Dom parameterDefaults = defaultConfiguration.getChild(parameter.getName()); parameterConfiguration = Xpp3Dom.mergeXpp3Dom(parameterConfiguration, parameterDefaults, Boolean.TRUE); if (parameterConfiguration != null) { parameterConfiguration = new Xpp3Dom(parameterConfiguration, parameter.getName()); if (StringUtils.isEmpty(parameterConfiguration.getAttribute("implementation")) && StringUtils.isNotEmpty(parameter.getImplementation())) { parameterConfiguration.setAttribute("implementation", parameter.getImplementation()); } finalConfiguration.addChild(parameterConfiguration); } } } mojoExecution.setConfiguration(finalConfiguration); } /** * @param artifactId * @param pom * @return the plexus configuration * @throws Exception */ protected PlexusConfiguration extractPluginConfiguration(String artifactId, File pom) throws Exception { Reader reader = ReaderFactory.newXmlReader(pom); Xpp3Dom pomDom = Xpp3DomBuilder.build(reader); return extractPluginConfiguration(artifactId, pomDom); } /** * @param artifactId * @param pomDom * @return the plexus configuration * @throws Exception */ protected PlexusConfiguration extractPluginConfiguration(String artifactId, Xpp3Dom pomDom) throws Exception { Xpp3Dom pluginConfigurationElement = null; Xpp3Dom buildElement = pomDom.getChild("build"); if (buildElement != null) { Xpp3Dom pluginsRootElement = buildElement.getChild("plugins"); if (pluginsRootElement != null) { Xpp3Dom[] pluginElements = pluginsRootElement.getChildren(); for (Xpp3Dom pluginElement : pluginElements) { String pluginElementArtifactId = pluginElement.getChild("artifactId").getValue(); if (pluginElementArtifactId.equals(artifactId)) { pluginConfigurationElement = pluginElement.getChild("configuration"); break; } } if (pluginConfigurationElement == null) { throw new ConfigurationException("Cannot find a configuration element for a plugin with an " + "artifactId of " + artifactId + "."); } } } if (pluginConfigurationElement == null) { throw new ConfigurationException( "Cannot find a configuration element for a plugin with an artifactId of " + artifactId + "."); } return new XmlPlexusConfiguration(pluginConfigurationElement); } /** * Configure the mojo * * @param mojo * @param artifactId * @param pom * @return a Mojo instance * @throws Exception */ protected Mojo configureMojo(Mojo mojo, String artifactId, File pom) throws Exception { validateContainerStatus(); PlexusConfiguration pluginConfiguration = extractPluginConfiguration(artifactId, pom); ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub(); configurator.configureComponent(mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm()); return mojo; } /** * Configure the mojo with the given plexus configuration * * @param mojo * @param pluginConfiguration * @return a Mojo instance * @throws Exception */ protected Mojo configureMojo(Mojo mojo, PlexusConfiguration pluginConfiguration) throws Exception { validateContainerStatus(); ExpressionEvaluator evaluator = new ResolverExpressionEvaluatorStub(); configurator.configureComponent(mojo, pluginConfiguration, evaluator, getContainer().getContainerRealm()); return mojo; } /** * Convenience method to obtain the value of a variable on a mojo that might not have a getter. * * NOTE: the caller is responsible for casting to to what the desired type is. * * @param object * @param variable * @return object value of variable * @throws IllegalArgumentException */ protected Object getVariableValueFromObject(Object object, String variable) throws IllegalAccessException { Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass()); field.setAccessible(true); return field.get(object); } /** * Convenience method to obtain all variables and values from the mojo (including its superclasses) * * Note: the values in the map are of type Object so the caller is responsible for casting to desired types. * * @param object * @return map of variable names and values */ protected Map<String, Object> getVariablesAndValuesFromObject(Object object) throws IllegalAccessException { return getVariablesAndValuesFromObject(object.getClass(), object); } /** * Convenience method to obtain all variables and values from the mojo (including its superclasses) * * Note: the values in the map are of type Object so the caller is responsible for casting to desired types. * * @param clazz * @param object * @return map of variable names and values */ protected Map<String, Object> getVariablesAndValuesFromObject(Class<?> clazz, Object object) throws IllegalAccessException { Map<String, Object> map = new HashMap<String, Object>(); Field[] fields = clazz.getDeclaredFields(); AccessibleObject.setAccessible(fields, true); for (Field field : fields) { map.put(field.getName(), field.get(object)); } Class<?> superclass = clazz.getSuperclass(); if (!Object.class.equals(superclass)) { map.putAll(getVariablesAndValuesFromObject(superclass, object)); } return map; } /** * Convenience method to set values to variables in objects that don't have setters * * @param object * @param variable * @param value * @throws IllegalAccessException */ protected void setVariableValueToObject(Object object, String variable, Object value) throws IllegalAccessException { Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses(variable, object.getClass()); field.setAccessible(true); field.set(object, value); } /** * sometimes the parent element might contain the correct value so generalize that access * * TODO find out where this is probably done elsewhere * * @param pluginPomDom * @param element * @return * @throws Exception */ private String resolveFromRootThenParent(Xpp3Dom pluginPomDom, String element) throws Exception { Xpp3Dom elementDom = pluginPomDom.getChild(element); // parent might have the group Id so resolve it if (elementDom == null) { Xpp3Dom pluginParentDom = pluginPomDom.getChild("parent"); if (pluginParentDom != null) { elementDom = pluginParentDom.getChild(element); if (elementDom == null) { throw new Exception("unable to determine " + element); } return elementDom.getValue(); } throw new Exception("unable to determine " + element); } return elementDom.getValue(); } /** * We should make sure this is called in each method that makes use of the container, * otherwise we throw ugly NPE's * * crops up when the subclassing code defines the setUp method but doesn't call super.setUp() * * @throws Exception */ private void validateContainerStatus() throws Exception { if (getContainer() != null) { return; } throw new Exception("container is null, make sure super.setUp() is called"); } }