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