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