1   package com.atlassian.maven.plugins.amps;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.lang.reflect.InvocationTargetException;
6   import java.lang.reflect.Method;
7   import java.util.List;
8   
9   import com.atlassian.maven.plugins.amps.util.GoogleAmpsTracker;
10  
11  import org.apache.maven.artifact.Artifact;
12  import org.apache.maven.execution.MavenSession;
13  import org.apache.maven.execution.ReactorManager;
14  import org.apache.maven.model.Plugin;
15  import org.apache.maven.model.PluginManagement;
16  import org.apache.maven.model.locator.DefaultModelLocator;
17  import org.apache.maven.plugin.MojoExecutionException;
18  import org.apache.maven.plugin.MojoFailureException;
19  import org.apache.maven.project.MavenProject;
20  import org.apache.maven.project.MavenProjectBuilder;
21  import org.apache.maven.project.ProjectBuilder;
22  import org.apache.maven.project.ProjectBuilderConfiguration;
23  import org.apache.maven.project.ProjectBuildingException;
24  import org.apache.maven.project.ProjectBuildingRequest;
25  import org.apache.maven.project.ProjectBuildingResult;
26  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
27  import org.codehaus.plexus.util.xml.Xpp3Dom;
28  import org.jfrog.maven.annomojo.annotations.MojoGoal;
29  import org.jfrog.maven.annomojo.annotations.MojoParameter;
30  import org.jfrog.maven.annomojo.annotations.MojoRequiresProject;
31  
32  import static java.util.Collections.singletonList;
33  
34  /**
35   * Run the webapp without a plugin project
36   */
37  @MojoGoal ("run-standalone")
38  @MojoRequiresProject (false)
39  public class RunStandaloneMojo extends AbstractProductHandlerMojo
40  {
41      private final String
42          GROUP_ID = "com.atlassian.amps",
43          ARTIFACT_ID = "standalone";
44  
45      @MojoParameter (expression = "${component.org.apache.maven.project.MavenProjectBuilder}", required = true, readonly = true)
46      private MavenProjectBuilder projectBuilder;
47  
48      private Artifact getStandaloneArtifact()
49      {
50          final String version = getPluginInformation().getVersion();
51          return artifactFactory.createProjectArtifact(GROUP_ID, ARTIFACT_ID, version);
52      }
53  
54      protected String getAmpsGoal()
55      {
56          return "run";
57      }
58  
59      protected void doExecute() throws MojoExecutionException, MojoFailureException
60      {
61          getGoogleTracker().track(GoogleAmpsTracker.RUN_STANDALONE);
62  
63          try
64          {
65              MavenGoals goals;
66              Xpp3Dom configuration;
67  
68              try
69              {
70                  /* Maven 3 */
71                  Object o = getMavenContext().getSession().lookup("org.apache.maven.project.ProjectBuilder");
72                  goals = createMavenGoals((ProjectBuilder) o);
73  
74                  /* When we run with Maven 3 the configuration from the pom isn't automatically picked up
75                   * by the mojo executor. Grab it manually from pluginManagement.
76                   */
77                  PluginManagement mgmt = goals.getContextProject().getBuild().getPluginManagement();
78                  Plugin plugin = (Plugin) mgmt.getPluginsAsMap().get("com.atlassian.maven.plugins:maven-amps-plugin");
79  
80                  configuration = (Xpp3Dom) plugin.getConfiguration();
81              }
82              catch (ComponentLookupException e)
83              {
84                  /* Maven 2 */
85                  goals = createMavenGoals(projectBuilder);
86                  configuration = new Xpp3Dom("configuration");
87              }
88  
89              goals.executeAmpsRecursively(getPluginInformation().getVersion(), getAmpsGoal(), configuration);
90          }
91          catch (Exception e)
92          {
93              throw new MojoExecutionException(e.getMessage(), e);
94          }
95      }
96  
97      protected MavenGoals createMavenGoals(MavenProjectBuilder projectBuilder) throws MojoExecutionException, MojoFailureException
98      {
99          final String version = getPluginInformation().getVersion();
100         final Artifact artifact = artifactFactory.createProjectArtifact(GROUP_ID, ARTIFACT_ID, version);
101         try
102         {
103             // overall goal here is to create a new MavenContext / MavenGoals for the standalone project
104             final MavenContext oldContext = getMavenContext();
105 
106             // construct new project for new context
107             final MavenProject
108                 oldProject = oldContext.getProject(),
109                 newProject = projectBuilder.buildFromRepository(artifact, repositories, localRepository);
110 
111             // horrible hack #1: buildFromRepository() doesn't actually set the project's remote repositories
112             newProject.setRemoteArtifactRepositories(oldProject.getRemoteArtifactRepositories());
113             newProject.setPluginArtifactRepositories(oldProject.getPluginArtifactRepositories());
114 
115             // horrible hack #2: we need to modify the session to use the new project as its reactor
116             final List<MavenProject> newReactor = singletonList(newProject);
117             final MavenSession
118                 oldSession = oldContext.getSession(),
119                 newSession = new MavenSession(
120                     oldSession.getContainer(),
121                     oldSession.getSettings(),
122                     oldSession.getLocalRepository(),
123                     oldSession.getEventDispatcher(),
124                     new ReactorManager(newReactor),
125                     oldSession.getGoals(),
126                     oldSession.getExecutionRootDirectory(),
127                     oldSession.getExecutionProperties(),
128                     oldSession.getUserProperties(),
129                     oldSession.getStartTime()
130                 );
131 
132             // horrible hack #3: we need to create a base directory from scratch, and convince the project to like it
133             final String baseDir = System.getProperty("user.dir") + "/amps-standalone/";
134             newProject.setFile(new File(baseDir, "pom.xml"));
135 
136             newProject.getProperties().putAll(oldProject.getProperties());
137 
138             ProjectBuilderConfiguration projectBuilderConfiguration =
139                     getProjectBuilderConfigurationFromMavenSession(newSession);
140 
141             projectBuilder.calculateConcreteState(newProject, projectBuilderConfiguration);
142 
143             // finally, execute run goal against standalone project
144             final MavenContext newContext = oldContext.with(
145                 newProject,
146                 newReactor,
147                 newSession);
148             return new MavenGoals(newContext);
149         }
150         catch (Exception e)
151         {
152             throw new MojoExecutionException(e.getMessage(), e);
153         }
154     }
155 
156     /**
157      * MavenSession.getProjectBuilderConfiguration() works at runtime with Maven 2 but isn't
158      * available at compile time when we build with Maven 3 artifacts.
159      */
160     private static ProjectBuilderConfiguration getProjectBuilderConfigurationFromMavenSession(MavenSession session)
161         throws MojoExecutionException, InvocationTargetException, IllegalAccessException
162     {
163         try
164         {
165             Method m = MavenSession.class.getMethod("getProjectBuilderConfiguration");
166             return (ProjectBuilderConfiguration) m.invoke(session);
167         }
168         catch (NoSuchMethodException e)
169         {
170             throw new MojoExecutionException("Maven 3 is not supported for run-standalone", e);
171         }
172     }
173 
174     protected MavenGoals createMavenGoals(ProjectBuilder projectBuilder)
175             throws MojoExecutionException, MojoFailureException, ProjectBuildingException,
176             IOException
177     {
178         // overall goal here is to create a new MavenContext / MavenGoals for the standalone project
179         final MavenContext oldContext = getMavenContext();
180 
181         MavenSession oldSession = oldContext.getSession();
182 
183         File base = new File("amps-standalone").getAbsoluteFile();
184 
185         ProjectBuildingRequest pbr = oldSession.getProjectBuildingRequest();
186 
187         // hack #1 from before
188         pbr.setRemoteRepositories(oldSession.getCurrentProject().getRemoteArtifactRepositories());
189         pbr.setPluginArtifactRepositories(oldSession.getCurrentProject().getPluginArtifactRepositories());
190 
191         pbr.getSystemProperties().setProperty("project.basedir", base.getPath());
192 
193         ProjectBuildingResult result = projectBuilder.build(getStandaloneArtifact(), false, pbr);
194 
195         final List<MavenProject> newReactor = singletonList(result.getProject());
196 
197         MavenSession newSession = oldSession.clone();
198         newSession.setProjects(newReactor);
199 
200         // Horrible hack #3 from before
201         result.getProject().setFile(new DefaultModelLocator().locatePom(base));
202 
203         final MavenContext newContext = oldContext.with(
204             result.getProject(),
205             newReactor,
206             newSession);
207 
208         return new MavenGoals(newContext);
209     }
210 }