1   package com.atlassian.maven.plugins.amps.product;
2   
3   import static com.atlassian.maven.plugins.amps.util.FileUtils.doesFileNameMatchArtifact;
4   import static com.atlassian.maven.plugins.amps.util.ZipUtils.unzip;
5   
6   import java.io.File;
7   import java.io.IOException;
8   import java.util.ArrayList;
9   import java.util.Collection;
10  import java.util.Iterator;
11  import java.util.List;
12  import java.util.Map;
13  
14  import org.apache.commons.io.FileUtils;
15  import org.apache.commons.lang.StringUtils;
16  import org.apache.maven.plugin.MojoExecutionException;
17  import org.apache.maven.project.MavenProject;
18  
19  import com.atlassian.maven.plugins.amps.MavenGoals;
20  import com.atlassian.maven.plugins.amps.Product;
21  import com.atlassian.maven.plugins.amps.ProductArtifact;
22  
23  public abstract class AbstractWebappProductHandler extends AbstractProductHandler
24  {
25      private final PluginProvider pluginProvider;
26  
27      public AbstractWebappProductHandler(final MavenProject project, final MavenGoals goals, PluginProvider pluginProvider)
28      {
29          super(project, goals);
30          this.pluginProvider = pluginProvider;
31      }
32  
33      public int start(final Product ctx) throws MojoExecutionException
34      {
35          // Copy the webapp war to target
36          final File webappWar = goals.copyWebappWar(ctx.getId(), getBaseDirectory(ctx.getInstanceId()),
37                  new ProductArtifact(getArtifact().getGroupId(), getArtifact().getArtifactId(), ctx.getVersion()));
38  
39          final File homeDir = extractAndProcessHomeDirectory(ctx);
40  
41          final File combinedWebappWar = addArtifactsAndOverrides(ctx, homeDir, webappWar);
42  
43          final Map<String, String> properties = mergeSystemProperties(ctx);
44  
45          return goals.startWebapp(ctx.getInstanceId(), combinedWebappWar, properties, getExtraContainerDependencies(), ctx);
46      }
47  
48      public void stop(final Product ctx) throws MojoExecutionException
49      {
50          goals.stopWebapp(ctx.getInstanceId(), ctx.getContainerId());
51      }
52  
53      private File addArtifactsAndOverrides(final Product ctx, final File homeDir, final File webappWar) throws MojoExecutionException
54      {
55          try
56          {
57              final String webappDir = new File(getBaseDirectory(ctx.getInstanceId()), "webapp").getAbsolutePath();
58              if (!new File(webappDir).exists())
59              {
60                  unzip(webappWar, webappDir);
61              }
62  
63              File pluginsDir = getPluginsDirectory(webappDir, homeDir);
64              final File bundledPluginsDir = new File(getBaseDirectory(ctx.getInstanceId()), "bundled-plugins");
65  
66              bundledPluginsDir.mkdir();
67              // add bundled plugins
68              final File bundledPluginsZip = new File(webappDir, getBundledPluginPath(ctx));
69              if (bundledPluginsZip.exists())
70              {
71                  unzip(bundledPluginsZip, bundledPluginsDir.getPath());
72              }
73  
74              if (isStaticPlugin())
75              {
76                  pluginsDir = new File(webappDir, "WEB-INF/lib");
77              }
78  
79              if (pluginsDir == null)
80              {
81                  pluginsDir = bundledPluginsDir;
82              }
83  
84              pluginsDir.mkdirs();
85  
86              // add this plugin itself if enabled
87              if (ctx.isInstallPlugin())
88              {
89                  addThisPluginToDirectory(pluginsDir);
90                  addTestPluginToDirectory(pluginsDir);
91              }
92  
93              // add plugins2 plugins if necessary
94              if (!isStaticPlugin())
95              {
96                  addArtifactsToDirectory(goals, pluginProvider.provide(ctx), pluginsDir);
97              }
98  
99              // add plugins1 plugins
100             List<ProductArtifact> artifacts = new ArrayList<ProductArtifact>();
101             artifacts.addAll(getDefaultLibPlugins());
102             artifacts.addAll(ctx.getLibArtifacts());
103             addArtifactsToDirectory(goals, artifacts, new File(webappDir, "WEB-INF/lib"));
104 
105             artifacts = new ArrayList<ProductArtifact>();
106             artifacts.addAll(getDefaultBundledPlugins());
107             artifacts.addAll(ctx.getBundledArtifacts());
108 
109             addArtifactsToDirectory(goals, artifacts, bundledPluginsDir);
110 
111             if (bundledPluginsDir.list().length > 0)
112             {
113                 com.atlassian.core.util.FileUtils.createZipFile(bundledPluginsDir, bundledPluginsZip);
114             }
115 
116             // add log4j.properties file if specified
117             if (ctx.getLog4jProperties() != null)
118             {
119                 FileUtils.copyFile(ctx.getLog4jProperties(), new File(webappDir, "WEB-INF/classes/log4j.properties"));
120             }
121 
122             // override war files
123             try
124             {
125                 addOverrides(new File(webappDir), ctx.getInstanceId());
126             }
127             catch (IOException e)
128             {
129                 throw new MojoExecutionException("Unable to override WAR files using src/test/resources/" + ctx.getInstanceId() + "-app", e);
130             }
131 
132             final File warFile = new File(webappWar.getParentFile(), getId() + ".war");
133             com.atlassian.core.util.FileUtils.createZipFile(new File(webappDir), warFile);
134             return warFile;
135 
136         }
137         catch (final Exception e)
138         {
139             e.printStackTrace();
140             throw new MojoExecutionException(e.getMessage());
141         }
142     }
143 
144     private File getBaseDirectory(String instanceId)
145     {
146         final File dir = new File(project.getBuild().getDirectory(), instanceId);
147         dir.mkdir();
148         return dir;
149     }
150 
151     private File extractAndProcessHomeDirectory(final Product ctx) throws MojoExecutionException
152     {
153         if (getTestResourcesArtifact() != null)
154         {
155 
156             final File outputDir = getBaseDirectory(ctx.getInstanceId());
157             final File homeDir = new File(outputDir, "home");
158 
159             // Only create the home dir if it doesn't exist
160             if (!homeDir.exists())
161             {
162 
163                 //find and extract productHomeZip
164                 final File productHomeZip = getProductHomeZip(ctx, outputDir);
165                 extractProductHomeZip(productHomeZip, homeDir, ctx, outputDir);
166 
167                 // just in case
168                 homeDir.mkdir();
169                 processHomeDirectory(ctx, homeDir);
170             }
171 
172             // Always override files regardless of home directory existing or not
173             try
174             {
175                 overrideAndPatchHomeDir(homeDir, ctx.getInstanceId());
176             }
177             catch (IOException e)
178             {
179                 throw new MojoExecutionException("Unable to override files using src/test/resources", e);
180             }
181 
182             return homeDir;
183         } else
184         {
185             return getHomeDirectory(ctx);
186         }
187     }
188 
189     private File getProductHomeZip(final Product ctx, final File outputDir) throws MojoExecutionException
190     {
191         File productHomeZip = null;
192         String dpath = ctx.getDataPath();
193 
194         //use custom zip if supplied
195         if (StringUtils.isNotBlank(dpath))
196         {
197             File customHomeZip = new File(dpath);
198 
199             if (customHomeZip.exists())
200             {
201                 productHomeZip = customHomeZip;
202             }
203         }
204 
205         //if we didn't find a custom zip, use the default
206         if (productHomeZip == null)
207         {
208             productHomeZip = goals.copyHome(outputDir,
209                     new ProductArtifact(
210                             getTestResourcesArtifact().getGroupId(),
211                             getTestResourcesArtifact().getArtifactId(),
212                             ctx.getDataVersion()));
213         }
214 
215         return productHomeZip;
216     }
217 
218     private void extractProductHomeZip(File productHomeZip, File homeDir,
219                                        Product ctx, File outputDir)
220             throws MojoExecutionException
221     {
222         final File tmpDir = new File(getBaseDirectory(ctx.getInstanceId()), "tmp-resources");
223         tmpDir.mkdir();
224 
225         try
226         {
227             unzip(productHomeZip, tmpDir.getPath());
228             FileUtils.copyDirectory(tmpDir.listFiles()[0], outputDir, true);
229             File tmp = new File(outputDir, ctx.getId() + "-home");
230             FileUtils.moveDirectory(tmp, homeDir);
231         }
232         catch (final IOException ex)
233         {
234             throw new MojoExecutionException("Unable to copy home directory", ex);
235         }
236     }
237 
238     private void overrideAndPatchHomeDir(File homeDir, final String productId) throws IOException
239     {
240         final File srcDir = new File(project.getBasedir(), "src/test/resources/" + productId + "-home");
241         final File outputDir = new File(getBaseDirectory(productId), "home");
242         if (srcDir.exists() && outputDir.exists())
243         {
244             FileUtils.copyDirectory(srcDir, homeDir);
245         }
246     }
247 
248     private void addOverrides(File webappDir, final String productId) throws IOException
249     {
250         final File srcDir = new File(project.getBasedir(), "src/test/resources/" + productId + "-app");
251         if (srcDir.exists() && webappDir.exists())
252         {
253             FileUtils.copyDirectory(srcDir, webappDir);
254         }
255     }
256 
257     private void addArtifactsToDirectory(final MavenGoals goals, final List<ProductArtifact> artifacts, final File pluginsDir) throws MojoExecutionException
258     {
259         // first remove plugins from the webapp that we want to update
260         if (pluginsDir.isDirectory() && pluginsDir.exists())
261         {
262             for (final Iterator<?> iterateFiles = FileUtils.iterateFiles(pluginsDir, null, false); iterateFiles.hasNext();)
263             {
264                 final File file = (File) iterateFiles.next();
265                 for (final ProductArtifact webappArtifact : artifacts)
266                 {
267                     if (!file.isDirectory() && doesFileNameMatchArtifact(file.getName(), webappArtifact.getArtifactId()))
268                     {
269                         file.delete();
270                     }
271                 }
272             }
273         }
274         // copy the all the plugins we want in the webapp
275         if (!artifacts.isEmpty())
276         {
277             goals.copyPlugins(pluginsDir, artifacts);
278         }
279     }
280 
281     protected abstract void processHomeDirectory(Product ctx, File homeDir) throws MojoExecutionException;
282 
283     protected abstract ProductArtifact getTestResourcesArtifact();
284 
285     protected abstract Collection<ProductArtifact> getDefaultBundledPlugins();
286 
287     protected abstract Collection<ProductArtifact> getDefaultLibPlugins();
288 
289     protected abstract String getBundledPluginPath(Product ctx);
290 
291     protected abstract File getPluginsDirectory(String webappDir, File homeDir);
292 
293     protected abstract List<ProductArtifact> getExtraContainerDependencies();
294 
295     protected abstract ProductArtifact getArtifact();
296 
297 }