1 package com.atlassian.maven.plugins.amps.product;
2
3 import java.io.File;
4
5 import java.io.IOException;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13
14 import com.atlassian.maven.plugins.amps.AbstractProductHandlerMojo;
15 import com.atlassian.maven.plugins.amps.MavenContext;
16 import com.atlassian.maven.plugins.amps.MavenGoals;
17 import com.atlassian.maven.plugins.amps.Product;
18 import com.atlassian.maven.plugins.amps.ProductArtifact;
19 import com.atlassian.maven.plugins.amps.util.ConfigFileUtils;
20
21 import com.atlassian.maven.plugins.amps.util.JvmArgsFix;
22 import com.google.common.base.Function;
23 import com.google.common.base.Joiner;
24 import com.google.common.collect.Iterables;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.maven.plugin.MojoExecutionException;
28
29 import static com.atlassian.maven.plugins.amps.util.FileUtils.doesFileNameMatchArtifact;
30 import static com.atlassian.maven.plugins.amps.util.ZipUtils.unzip;
31 import static org.apache.commons.io.FileUtils.copyDirectory;
32 import static org.apache.commons.io.FileUtils.copyFile;
33 import static org.apache.commons.io.FileUtils.iterateFiles;
34 import static org.apache.commons.io.FileUtils.moveDirectory;
35 import static org.apache.commons.io.FileUtils.readFileToString;
36 import static com.atlassian.maven.plugins.amps.util.ProjectUtils.createDirectory;
37
38 public abstract class AbstractProductHandler extends AmpsProductHandler
39 {
40 private final PluginProvider pluginProvider;
41
42 protected AbstractProductHandler(MavenContext context, MavenGoals goals, PluginProvider pluginProvider)
43 {
44 super(context, goals);
45 this.pluginProvider = pluginProvider;
46 }
47
48
49
50
51
52 public final int start(final Product ctx) throws MojoExecutionException
53 {
54 final File homeDir = extractAndProcessHomeDirectory(ctx);
55
56 final File extractedApp = extractApplication(ctx, homeDir);
57
58 final File finalApp = addArtifactsAndOverrides(ctx, homeDir, extractedApp);
59
60
61 Map<String, String> systemProperties = mergeSystemProperties(ctx);
62
63 return startApplication(ctx, finalApp, homeDir, systemProperties);
64 }
65
66 protected final File extractAndProcessHomeDirectory(final Product ctx) throws MojoExecutionException
67 {
68 final File homeDir = getHomeDirectory(ctx);
69
70
71 if (StringUtils.isNotBlank(ctx.getDataHome()))
72 {
73
74 return homeDir;
75 }
76
77
78 final File productHomeData = getProductHomeData(ctx);
79 if (productHomeData != null)
80 {
81
82
83 if (!homeDir.exists())
84 {
85 extractProductHomeData(productHomeData, homeDir, ctx);
86
87
88 homeDir.mkdir();
89 processHomeDirectory(ctx, homeDir);
90 }
91
92
93 overrideAndPatchHomeDir(homeDir, ctx);
94 }
95 return homeDir;
96 }
97
98 protected void extractProductHomeData(File productHomeData, File homeDir, Product ctx)
99 throws MojoExecutionException
100 {
101 final File tmpDir = new File(getBaseDirectory(ctx), "tmp-resources");
102 tmpDir.mkdir();
103
104 try
105 {
106 if (productHomeData.isFile())
107 {
108 File tmp = new File(getBaseDirectory(ctx), ctx.getId() + "-home");
109
110 unzip(productHomeData, tmpDir.getPath());
111
112 File[] topLevelFiles = tmpDir.listFiles();
113 if (topLevelFiles.length != 1)
114 {
115 Iterable<String> filenames = Iterables.transform(Arrays.asList(topLevelFiles), new Function<File, String>(){
116 @Override
117 public String apply(File from)
118 {
119 return from.getName();
120 }
121 });
122 throw new MojoExecutionException("Expected a single top-level directory in test resources. Got: "
123 + Joiner.on(", ").join(filenames));
124 }
125
126 copyDirectory(topLevelFiles[0], getBaseDirectory(ctx), true);
127 moveDirectory(tmp, homeDir);
128 }
129 else if (productHomeData.isDirectory())
130 {
131 copyDirectory(productHomeData, homeDir);
132 }
133 }
134 catch (final IOException ex)
135 {
136 throw new MojoExecutionException("Unable to copy home directory", ex);
137 }
138 }
139
140
141
142
143
144
145 private final File addArtifactsAndOverrides(final Product ctx, final File homeDir, final File app) throws MojoExecutionException
146 {
147 try
148 {
149 final File appDir;
150 if (app.isFile())
151 {
152 appDir = new File(getBaseDirectory(ctx), "webapp");
153 if (!appDir.exists())
154 {
155 unzip(app, appDir.getAbsolutePath());
156 }
157 }
158 else
159 {
160 appDir = app;
161 }
162
163 addArtifacts(ctx, homeDir, appDir);
164
165
166 try
167 {
168 addOverrides(appDir, ctx);
169 customiseInstance(ctx, homeDir, appDir);
170 fixJvmArgs(ctx);
171 }
172 catch (IOException e)
173 {
174 throw new MojoExecutionException("Unable to override WAR files using src/test/resources/" + ctx.getInstanceId() + "-app", e);
175 }
176
177 if (app.isFile())
178 {
179 final File warFile = new File(app.getParentFile(), getId() + ".war");
180 com.atlassian.core.util.FileUtils.createZipFile(appDir, warFile);
181 return warFile;
182 }
183 else
184 {
185 return appDir;
186 }
187
188 }
189 catch (final Exception e)
190 {
191 throw new MojoExecutionException(e.getMessage(), e);
192 }
193 }
194
195
196
197
198
199
200
201
202
203
204
205 protected void customiseInstance(Product ctx, File homeDir, File explodedWarDir) throws MojoExecutionException
206 {
207
208 }
209
210
211
212
213
214 protected void fixJvmArgs(Product ctx)
215 {
216 final String jvmArgs = JvmArgsFix.defaults()
217 .apply(ctx.getJvmArgs());
218 ctx.setJvmArgs(jvmArgs);
219 }
220
221 private void addArtifacts(final Product ctx, final File homeDir, final File appDir)
222 throws IOException, MojoExecutionException, Exception
223 {
224 File pluginsDir = getUserInstalledPluginsDirectory(appDir, homeDir);
225 final File bundledPluginsDir = new File(getBaseDirectory(ctx), "bundled-plugins");
226
227 bundledPluginsDir.mkdir();
228
229 final File bundledPluginsZip = new File(appDir, getBundledPluginPath(ctx));
230 if (bundledPluginsZip.exists())
231 {
232 unzip(bundledPluginsZip, bundledPluginsDir.getPath());
233 }
234
235 if (isStaticPlugin())
236 {
237 if (!supportsStaticPlugins())
238 {
239 throw new MojoExecutionException("According to your atlassian-plugin.xml file, this plugin is not " +
240 "atlassian-plugins version 2. This app currently only supports atlassian-plugins " +
241 "version 2.");
242 }
243 pluginsDir = new File(appDir, "WEB-INF/lib");
244 }
245
246 if (pluginsDir == null)
247 {
248 pluginsDir = bundledPluginsDir;
249 }
250
251 createDirectory(pluginsDir);
252
253
254 if (ctx.isInstallPlugin())
255 {
256 addThisPluginToDirectory(pluginsDir);
257 addTestPluginToDirectory(pluginsDir);
258 }
259
260
261 if (!isStaticPlugin())
262 {
263 addArtifactsToDirectory(pluginProvider.provide(ctx), pluginsDir);
264 }
265
266
267 List<ProductArtifact> artifacts = new ArrayList<ProductArtifact>();
268 artifacts.addAll(getDefaultLibPlugins());
269 artifacts.addAll(ctx.getLibArtifacts());
270 addArtifactsToDirectory(artifacts, new File(appDir, "WEB-INF/lib"));
271
272 artifacts = new ArrayList<ProductArtifact>();
273 artifacts.addAll(getDefaultBundledPlugins());
274 artifacts.addAll(ctx.getBundledArtifacts());
275
276 addArtifactsToDirectory(artifacts, bundledPluginsDir);
277
278 if (bundledPluginsDir.list().length > 0)
279 {
280 com.atlassian.core.util.FileUtils.createZipFile(bundledPluginsDir, bundledPluginsZip);
281 }
282
283 if (ctx.getLog4jProperties() != null && getLog4jPropertiesPath() != null)
284 {
285 copyFile(ctx.getLog4jProperties(), new File(appDir, getLog4jPropertiesPath()));
286 }
287 }
288
289
290
291
292 protected void processHomeDirectory(Product ctx, File snapshotDir) throws MojoExecutionException
293 {
294 ConfigFileUtils.replace(getConfigFiles(ctx, snapshotDir), getReplacements(ctx), false, log);
295 }
296
297 abstract protected File extractApplication(Product ctx, File homeDir) throws MojoExecutionException;
298 abstract protected int startApplication(Product ctx, File app, File homeDir, Map<String, String> properties) throws MojoExecutionException;
299 abstract protected boolean supportsStaticPlugins();
300 abstract protected Collection<? extends ProductArtifact> getDefaultBundledPlugins();
301 abstract protected Collection<? extends ProductArtifact> getDefaultLibPlugins();
302 abstract protected String getBundledPluginPath(Product ctx);
303 abstract protected File getUserInstalledPluginsDirectory(File webappDir, File homeDir);
304
305 protected String getLog4jPropertiesPath()
306 {
307 return null;
308 }
309
310 protected boolean isStaticPlugin() throws IOException
311 {
312 final File atlassianPluginXml = new File(project.getBasedir(), "src/main/resources/atlassian-plugin.xml");
313 if (atlassianPluginXml.exists())
314 {
315 String text = readFileToString(atlassianPluginXml);
316 return !text.contains("pluginsVersion=\"2\"") && !text.contains("plugins-version=\"2\"");
317 }
318 else
319 {
320
321 return false;
322 }
323 }
324
325 protected final void addThisPluginToDirectory(final File targetDir) throws IOException
326 {
327 final File thisPlugin = getPluginFile();
328
329 if (thisPlugin.exists())
330 {
331
332 for (final Iterator<?> iterateFiles = iterateFiles(targetDir, null, false); iterateFiles.hasNext();)
333 {
334 final File file = (File) iterateFiles.next();
335 if (doesFileNameMatchArtifact(file.getName(), project.getArtifactId()))
336 {
337 file.delete();
338 }
339 }
340
341
342 copyFile(thisPlugin, new File(targetDir, thisPlugin.getName()));
343 }
344 else
345 {
346 log.info("No plugin in the current project - " + thisPlugin.getAbsolutePath());
347 }
348 }
349
350 protected void addTestPluginToDirectory(final File targetDir) throws IOException
351 {
352 final File testPluginFile = getTestPluginFile();
353 if (testPluginFile.exists())
354 {
355
356 copyFile(testPluginFile, new File(targetDir, testPluginFile.getName()));
357 }
358
359 }
360
361 protected final File getPluginFile()
362 {
363 return new File(project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".jar");
364 }
365
366 protected File getTestPluginFile()
367 {
368 return new File(project.getBuild().getDirectory(), project.getBuild().getFinalName() + "-tests.jar");
369 }
370
371 protected final void addArtifactsToDirectory(final List<ProductArtifact> artifacts, final File pluginsDir) throws MojoExecutionException
372 {
373
374 if (!artifacts.isEmpty())
375 {
376
377 if (pluginsDir.isDirectory() && pluginsDir.exists())
378 {
379 for (final Iterator<?> iterateFiles = iterateFiles(pluginsDir, null, false); iterateFiles.hasNext();)
380 {
381 final File file = (File) iterateFiles.next();
382 for (final ProductArtifact webappArtifact : artifacts)
383 {
384 if (!file.isDirectory() && doesFileNameMatchArtifact(file.getName(), webappArtifact.getArtifactId()))
385 {
386 file.delete();
387 }
388 }
389 }
390 }
391 goals.copyPlugins(pluginsDir, artifacts);
392 }
393 }
394
395 protected final void addOverrides(File appDir, final Product ctx) throws IOException
396 {
397 final File srcDir = new File(project.getBasedir(), "src/test/resources/" + ctx.getInstanceId() + "-app");
398 if (srcDir.exists() && appDir.exists())
399 {
400 copyDirectory(srcDir, appDir);
401 }
402 }
403
404
405
406
407
408
409 protected final Map<String, String> mergeSystemProperties(Product ctx)
410 {
411 final Map<String, String> properties = new HashMap<String, String>();
412
413 properties.putAll(getSystemProperties(ctx));
414 for (Map.Entry<String, Object> entry : ctx.getSystemPropertyVariables().entrySet())
415 {
416 properties.put(entry.getKey(), (String) entry.getValue());
417 }
418 return properties;
419 }
420
421
422
423
424 protected abstract Map<String, String> getSystemProperties(Product ctx);
425
426
427
428
429 protected abstract ProductArtifact getArtifact();
430
431 }