View Javadoc
1   /**
2    * Copyright (C) 2008-2010 Matt Gumbley, DevZendo.org <http://devzendo.org>;
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  /**
18   * 
19   */
20  package org.devzendo.xplp;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.Properties;
25  import java.util.Set;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.plugin.AbstractMojo;
29  
30  /**
31   * Creates a Windows launcher directory structure.
32   * @author matt
33   *
34   */
35  public class WindowsLauncherCreator extends LauncherCreator {
36      private static final String LINE_SEPARATOR = System.getProperty("line.separator");
37      private static final String MSVCR71_DLL = "msvcr71.dll";
38      private final String mLauncherType;
39      private final String[] mJanelCustomLines;
40      private final String mJanelVersion;
41      private final String mJanelBits;
42      private final String mJanelDirectory;
43  
44      /**
45       * @param mojo the parent mojo class
46       * @param outputDirectory where to create the .app structure 
47       * @param mainClassName the main class
48       * @param applicationName the name of the application
49       * @param libraryDirectory where the libraries are stored
50       * @param transitiveArtifacts the set of transitive artifact dependencies
51       * @param resourceDirectories the project's resource directories
52       * @param parameterProperties the plugin configuration parameters, as properties
53       * @param systemProperties an array of name=value system properties
54       * @param vmArguments an array of arguments to the VM
55       * @param narClassifierTypes an array of NAR classifier:types
56       * @param launcherType the launcher type, Console or GUI.
57       * @param janelVersion the version of Janel, 3.0 or 4.2
58       * @param janelBits 32 or 64 bit Janel 4.2
59       * @param janelCustomLines an array of extra lines to be added to the launcher file
60       * @param janelDirectory root or bin - where to put the binaries, and do we need to relativise the library directory
61       */
62      public WindowsLauncherCreator(final AbstractMojo mojo,
63              final File outputDirectory,
64              final String mainClassName,
65              final String applicationName,
66              final String libraryDirectory,
67              final Set<Artifact> transitiveArtifacts,
68              final Set<File> resourceDirectories,
69              final Properties parameterProperties,
70              final String[] systemProperties, 
71              final String[] vmArguments, 
72              final String[] narClassifierTypes,
73              final String launcherType,
74              final String janelVersion,
75              final String janelBits,
76              final String[] janelCustomLines,
77              final String janelDirectory) {
78          super(mojo, outputDirectory, mainClassName,
79              applicationName, libraryDirectory,
80              transitiveArtifacts, resourceDirectories,
81              parameterProperties, systemProperties, vmArguments,
82              narClassifierTypes);
83          mLauncherType = launcherType;
84          mJanelCustomLines = janelCustomLines;
85          mJanelVersion = janelVersion;
86          mJanelBits = janelBits;
87          mJanelDirectory = janelDirectory;
88      }
89      
90      private void validate() {
91          if (mLauncherType == null || mLauncherType.length() == 0) {
92              final String message = "No launcherType specified - this is mandatory for Windows";
93              getMojo().getLog().warn(message);
94              throw new IllegalStateException(message);
95          }
96          if (!(mLauncherType.equals("Console") || mLauncherType.equals("GUI"))) {
97              final String message = "launcherType must be either 'Console' or 'GUI' (GUI is the default if not specified)";
98              getMojo().getLog().warn(message);
99              throw new IllegalStateException(message);
100         }
101         if (mJanelVersion.equals("3.0") || mJanelVersion.equals("4.2")) {
102             getMojo().getLog().info("Janel version:               " + mJanelVersion);
103         } else {
104             throw new IllegalStateException("Janel version must be 3.0 or 4.2");
105         }
106         if (mJanelBits.equals("32") || mJanelBits.equals("64")) {
107             getMojo().getLog().info("Janel bits:                  " + mJanelBits);
108         } else {
109             throw new IllegalStateException("Janel bits must be 32 or 64");
110         }
111         if (mJanelDirectory.equals("root") || mJanelDirectory.equals("bin")) {
112             getMojo().getLog().info("Janel bin/dll/lap directory: " + mJanelDirectory);
113         } else {
114             throw new IllegalStateException("Janel directory must be root or bin");
115         }
116     }
117 
118     /**
119      * {@inheritDoc}
120      */
121     @Override
122     public void createLauncher() throws IOException {
123         validate();
124         getParameterProperties().put("xplp.windowssystemproperties", systemPropertiesAsJanelLines(getSystemProperties()));
125         getParameterProperties().put("xplp.windowsvmarguments", stringsToSeparatedJanelLines(getVmArguments()));
126         getParameterProperties().put("xplp.janelcustomlines", stringsToSeparatedJanelLines(mJanelCustomLines));
127 
128         getMojo().getLog().info("Janel .EXE type:             " + mLauncherType);
129 
130         final boolean usingBinForBinaries = mJanelDirectory.equals("bin"); // could be 'root' instead
131         if (usingBinForBinaries) {
132             // A bit kludgy here, but when the .lap file has ${FOUND_EXE_FOLDER} in it, we DON'T INTERPOLATE IT
133             // or rather, we do.. to itself... then Janel can process it. Ew...
134             // A better 'fix' would be to call doNotInterpolate("FOUND_EXE_FOLDER") on the interpolator, but
135             // we don't have access to it directly here, without a fair amount of refactoring..
136             getParameterProperties().put("FOUND_EXE_FOLDER", "${FOUND_EXE_FOLDER}");
137             // Relativise the xplp.librarydirectory to the bin directory
138             getParameterProperties().put("xplp.librarydirectory", "${FOUND_EXE_FOLDER}\\..\\" + getLibraryDirectory());
139         }
140         // .. else just use the xplp.librarydirectory as-is, it's relative to the root
141 
142         final File osOutputDir = new File(getOutputDirectory(), "windows");
143         final File libDir = new File(osOutputDir, "lib");
144         final File binDir = usingBinForBinaries ? new File(osOutputDir, "bin") : osOutputDir;
145         osOutputDir.mkdirs();
146         libDir.mkdirs();
147         binDir.mkdirs(); // Will return false if !usingBinForBinaries, since it == osOutputDir which already exists. This is fine.
148         final boolean allDirsOK = osOutputDir.exists() && libDir.exists() && binDir.exists();
149         if (!allDirsOK) {
150             throw new IOException("Could not create required directories under " + getOutputDirectory().getAbsolutePath());
151         }
152         
153         final File outputJanelEXE = new File(binDir, getApplicationName() + ".exe");
154         final String janelEXEResource = "windows/" + janelExecutableName();
155         copyPluginResource(janelEXEResource, outputJanelEXE);
156         // TODO icon munging in the launcher .EXE
157         copyPluginResource("windows/" + MSVCR71_DLL, new File(binDir, MSVCR71_DLL));
158 
159         copyInterpolatedPluginResource("windows/launcher.lap", new File(binDir, getApplicationName() + ".lap"));
160 
161         copyTransitiveArtifacts(libDir);
162     }
163 
164     private String janelExecutableName() {
165         final String consoleOrWindows = mLauncherType.equals("Console") ? "Console" : "Windows";
166         if (mJanelVersion.equals("3.0")) {
167             // It's the original 3.0 version
168             final String originalDir = "3.0.2";
169             return originalDir + "/Janel" + consoleOrWindows + ".exe";
170         } else {
171             // It's the enhanced 4.2 version
172             final String enhancedDir = "4.2.0-98";
173             return enhancedDir + "/Janel" + consoleOrWindows + mJanelBits + ".exe";
174         }
175     }
176 
177     private String stringsToSeparatedJanelLines(final String[] strings) {
178         final StringBuilder stringLines = new StringBuilder();
179         if (strings.length > 0) {
180             for (final String string : strings) {
181                 stringLines.append(string);
182                 stringLines.append(LINE_SEPARATOR);
183             }
184         }
185         return stringLines.toString();
186     }
187 
188     private String systemPropertiesAsJanelLines(final String[] systemProperties) {
189         final StringBuilder sysPropLines = new StringBuilder();
190         if (systemProperties.length > 0) {
191             for (final String sysProp : systemProperties) {
192                 sysPropLines.append("-D");
193                 sysPropLines.append(sysProp);
194                 sysPropLines.append(LINE_SEPARATOR);
195             }
196         }
197         return sysPropLines.toString();
198     }
199 }