1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.devzendo.xplp;
18
19 import java.io.File;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Properties;
23 import java.util.Set;
24
25 import org.apache.maven.artifact.Artifact;
26 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
27 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
28 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
29 import org.apache.maven.model.Resource;
30 import org.apache.maven.plugin.AbstractMojo;
31 import org.apache.maven.plugin.MojoExecutionException;
32 import org.apache.maven.plugin.MojoFailureException;
33 import org.apache.maven.plugins.annotations.Component;
34 import org.apache.maven.plugins.annotations.LifecyclePhase;
35 import org.apache.maven.plugins.annotations.Mojo;
36 import org.apache.maven.plugins.annotations.Parameter;
37 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
38
39
40
41
42
43
44
45
46
47 @Mojo( name = "createlauncher",
48 defaultPhase = LifecyclePhase.GENERATE_RESOURCES )
49 public final class CreateLauncherMojo extends AbstractMojo {
50
51
52
53
54 @Parameter( defaultValue = "${project}", readonly = true)
55 private org.apache.maven.project.MavenProject mavenProject;
56
57 @Component()
58 private org.apache.maven.artifact.factory.ArtifactFactory artifactFactory;
59
60 @Component()
61 private org.apache.maven.artifact.resolver.ArtifactResolver artifactResolver;
62
63 @Parameter( defaultValue = "${localRepository}", readonly = true)
64 private org.apache.maven.artifact.repository.ArtifactRepository localRepository;
65
66 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", readonly = true)
67 private java.util.List<?> remoteRepositories;
68
69 @Component()
70 private ArtifactMetadataSource artifactMetadataSource;
71
72
73
74
75
76
77
78
79 @Parameter( defaultValue = "${xplp.os}", required = true )
80 private String os;
81
82
83
84
85
86
87
88
89 @Parameter( defaultValue = "${project.build.directory}")
90 private File outputDirectory;
91
92
93
94
95
96 @Parameter( defaultValue = "${xplp.mainclassname}", required = true )
97 private String mainClassName;
98
99
100
101
102
103
104
105
106
107 @Parameter( defaultValue = "${xplp.applicationname}", required = true )
108 private String applicationName;
109
110
111
112
113
114 @Parameter( defaultValue = "${xplp.librarydirectory}")
115 private String libraryDirectory = "lib";
116
117
118
119
120
121
122
123 @Parameter( defaultValue = "${xplp.systemproperty}")
124 private String[] systemProperties;
125
126
127
128
129
130
131 @Parameter( defaultValue = "${xplp.vmargument}")
132 private String[] vmArguments;
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 @Parameter( defaultValue = "${xplp.narClassifierType}")
148 private String[] narClassifierTypes;
149
150
151
152
153
154
155 @Parameter( defaultValue = "${xplp.launchertype}")
156 private String launcherType = "GUI";
157
158
159
160
161
162
163
164 @Parameter( defaultValue = "${xplp.filetype}")
165 private String fileType;
166
167
168
169
170 @Parameter( defaultValue = "${xplp.iconsfilename}")
171 private String iconsFileName;
172
173
174
175
176
177
178
179
180
181
182
183
184
185 @Parameter( defaultValue = "${xplp.bundlesignature}")
186 private String bundleSignature = "????";
187
188
189
190
191
192 @Parameter( defaultValue = "${xplp.bundleostype}")
193 private String bundleOsType;
194
195
196
197
198
199 @Parameter( defaultValue = "${xplp.bundletypename}")
200 private String bundleTypeName;
201
202
203
204
205
206
207
208
209
210 @Parameter( defaultValue = "${xplp.stubtype}")
211 private String stubType = "Apple";
212
213
214
215
216
217
218
219
220 @Deprecated
221 @Parameter( defaultValue = "${xplp.janeltype}")
222 private String janelType;
223
224
225
226
227
228 @Parameter( defaultValue = "${xplp.janelcustomline}")
229 private String[] janelCustomLines;
230
231
232
233
234
235
236
237
238
239
240
241 @Parameter( defaultValue = "${xplp.janelversion}")
242 private String janelVersion = "3.0";
243
244
245
246
247
248
249
250
251 @Parameter( defaultValue = "${xplp.janelbits}")
252 private String janelBits = "64";
253
254
255
256
257
258
259
260
261
262
263 @Parameter( defaultValue = "${xplp.janeldirectory}")
264 private String janelDirectory = "root";
265
266
267
268
269 public void execute() throws MojoExecutionException, MojoFailureException {
270 getLog().info("Cross Platform Launcher Plugin");
271 if (os == null || os.equals("none")) {
272 throw new MojoExecutionException("No <os>Windows|MacOSX|Linux</os> specified in the <configuration>");
273 }
274 if (janelType != null && !janelType.equals("")) {
275 throw new MojoExecutionException("The janelType attribute has been changed to launcherType in v0.2.1 of the plugin");
276 }
277 validateNarClassifierTypes();
278 final Set<Artifact> transitiveArtifacts = getTransitiveDependencies();
279 final Set<File> resourceDirectories = getResourceDirectories();
280 final Properties parameterProperties = getParameterProperties();
281 getLog().info("Operating System: " + os);
282 getLog().info("Output directory: " + outputDirectory);
283 getLog().info("Main class name: " + mainClassName);
284 getLog().info("Application name: " + applicationName);
285 getLog().info("Library directory: " + libraryDirectory);
286 getLog().info("System properties: " + dumpArray(systemProperties));
287 getLog().info("VM Arguments: " + dumpArray(vmArguments));
288 getLog().info("NAR Classifier:Types: " + dumpArray(narClassifierTypes));
289
290 LauncherCreator launcherCreator;
291 if (os.equals("MacOSX")) {
292 if (launcherType.equals("GUI")) {
293 launcherCreator = new MacOSXAppLauncherCreator(this,
294 outputDirectory, mainClassName, applicationName,
295 libraryDirectory, transitiveArtifacts,
296 resourceDirectories,
297 parameterProperties, systemProperties, vmArguments,
298 narClassifierTypes, launcherType,
299 fileType, iconsFileName, bundleSignature, bundleOsType,
300 bundleTypeName, stubType);
301 } else {
302 launcherCreator = new MacOSXScriptLauncherCreator(this,
303 outputDirectory, mainClassName, applicationName,
304 libraryDirectory, transitiveArtifacts,
305 resourceDirectories, parameterProperties, systemProperties,
306 vmArguments, narClassifierTypes, launcherType);
307 }
308 } else if (os.equals("Windows")) {
309 getLog().info("Janel custom lines: " + dumpArray(janelCustomLines));
310
311 launcherCreator = new WindowsLauncherCreator(this,
312 outputDirectory, mainClassName, applicationName,
313 libraryDirectory, transitiveArtifacts,
314 resourceDirectories, parameterProperties, systemProperties,
315 vmArguments, narClassifierTypes, launcherType, janelVersion, janelBits, janelCustomLines, janelDirectory);
316 } else if (os.equals("Linux")) {
317 launcherCreator = new LinuxLauncherCreator(this,
318 outputDirectory, mainClassName, applicationName,
319 libraryDirectory, transitiveArtifacts,
320 resourceDirectories, parameterProperties, systemProperties,
321 vmArguments, narClassifierTypes);
322 } else {
323 throw new MojoExecutionException("No <os>Windows|MacOSX|Linux</os> specified in the <configuration>");
324 }
325 try {
326 launcherCreator.createLauncher();
327 } catch (final Exception e) {
328 final StackTraceElement[] stackTrace = e.getStackTrace();
329 for (final StackTraceElement stackTraceElement : stackTrace) {
330 getLog().info(stackTraceElement.toString());
331 }
332 throw new MojoFailureException("Could not create launcher: " + e.getMessage());
333 }
334 }
335
336 private void validateNarClassifierTypes() throws MojoFailureException {
337 if (narClassifierTypes == null) {
338 narClassifierTypes = new String[0];
339 return;
340 }
341 boolean allOK = true;
342 for (final String narClassifierType : narClassifierTypes) {
343 if (!narClassifierType.matches("^\\S+:\\S+$")) {
344 getLog().error("NAR Classifier:Type '" + narClassifierType + "' is not of the form Classifier:Type");
345 allOK = false;
346 }
347 }
348 if (!allOK) {
349 throw new MojoFailureException("One or more NAR Classifier:Type parameters are incorrectly specified");
350 }
351 }
352
353 private String dumpArray(final Object[] objects) {
354 final StringBuilder sb = new StringBuilder();
355 if (objects != null) {
356 sb.append('[');
357 if (objects.length != 0) {
358 for (int i = 0; i < objects.length - 1; i++) {
359 sb.append(objects[i]);
360 sb.append(',');
361 }
362 sb.append(objects[objects.length - 1]);
363 }
364 sb.append(']');
365 }
366 return sb.toString();
367 }
368
369 private Properties getParameterProperties() {
370 final Properties properties = new Properties();
371
372
373 properties.put("xplp.os", nullToEmptyString(os));
374 properties.put("xplp.outputdirectory", nullToEmptyString(outputDirectory.getPath()));
375 properties.put("xplp.mainclassname", nullToEmptyString(mainClassName));
376 properties.put("xplp.applicationname", nullToEmptyString(applicationName));
377 properties.put("xplp.librarydirectory", nullToEmptyString(libraryDirectory));
378 properties.put("xplp.filetype", nullToEmptyString(fileType));
379 properties.put("xplp.iconsfilename", nullToEmptyString(iconsFileName));
380 properties.put("xplp.bundlesignature", nullToEmptyString(bundleSignature));
381 properties.put("xplp.bundleostype", nullToEmptyString(bundleOsType));
382 properties.put("xplp.bundletypename", nullToEmptyString(bundleTypeName));
383 properties.put("project.version", nullToEmptyString(mavenProject.getVersion()));
384 properties.put("project.description", nullToEmptyString(mavenProject.getDescription()));
385 return properties;
386 }
387
388 private String nullToEmptyString(final String in) {
389 return in == null ? "" : in;
390 }
391
392 @SuppressWarnings("unchecked")
393 private Set<File> getResourceDirectories() {
394 final HashSet<File> resourceDirs = new HashSet<File>();
395 final List<Resource> resources = mavenProject.getResources();
396 for (final Resource resource : resources) {
397 final String directory = resource.getDirectory();
398 final File directoryFile = new File(directory);
399 if (directoryFile.exists() && directoryFile.isDirectory()) {
400 resourceDirs.add(directoryFile);
401 }
402 }
403 return resourceDirs;
404 }
405
406 @SuppressWarnings("unchecked")
407 private Set<Artifact> getTransitiveDependencies() throws MojoFailureException {
408 getLog().info("Resolving transitive dependencies");
409 Set<?> artifacts;
410 try {
411 artifacts = mavenProject.createArtifacts(artifactFactory, null, null);
412
413
414
415
416
417
418
419
420 final Set<Artifact> result = artifactResolver.resolveTransitively(artifacts,
421 mavenProject.getArtifact(), localRepository, remoteRepositories,
422 artifactMetadataSource, null).getArtifacts();
423 for (final Artifact artifact : result) {
424 getLog().debug("Transitive artifact: " + artifact.toString());
425 getLog().debug(" File: " + artifact.getFile().getAbsolutePath());
426 }
427 getLog().info("Transitive dependencies resolved");
428 return result;
429 } catch (final InvalidDependencyVersionException e) {
430 final String message = "Invalid dependency version: " + e.getMessage();
431 getLog().warn(message);
432 throw new MojoFailureException(message);
433 } catch (final ArtifactResolutionException e) {
434 final String message = "Artifact failed to resolve: " + e.getMessage();
435 getLog().warn(message);
436 throw new MojoFailureException(message);
437 } catch (final ArtifactNotFoundException e) {
438 final String message = "Artifact not found: " + e.getMessage();
439 getLog().warn(message);
440 throw new MojoFailureException(message);
441 }
442 }
443 }