View Javadoc

1   /**
2    * The MIT License
3    * 
4    * Copyright 2006-2012 The Codehaus.
5    * 
6    * Permission is hereby granted, free of charge, to any person obtaining a copy of
7    * this software and associated documentation files (the "Software"), to deal in
8    * the Software without restriction, including without limitation the rights to
9    * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10   * of the Software, and to permit persons to whom the Software is furnished to do
11   * so, subject to the following conditions:
12   * 
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   * 
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  package org.codehaus.mojo.appassembler.daemon.jsw;
25  
26  import java.io.File;
27  import java.io.FileOutputStream;
28  import java.io.FileWriter;
29  import java.io.IOException;
30  import java.io.InputStream;
31  import java.io.InputStreamReader;
32  import java.io.Reader;
33  import java.util.ArrayList;
34  import java.util.HashMap;
35  import java.util.Iterator;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Properties;
39  
40  import org.apache.maven.artifact.Artifact;
41  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
42  import org.apache.maven.project.MavenProject;
43  import org.codehaus.mojo.appassembler.daemon.DaemonGenerationRequest;
44  import org.codehaus.mojo.appassembler.daemon.DaemonGenerator;
45  import org.codehaus.mojo.appassembler.daemon.DaemonGeneratorException;
46  import org.codehaus.mojo.appassembler.model.Daemon;
47  import org.codehaus.mojo.appassembler.model.Dependency;
48  import org.codehaus.mojo.appassembler.model.GeneratorConfiguration;
49  import org.codehaus.mojo.appassembler.util.FormattedProperties;
50  import org.codehaus.plexus.logging.AbstractLogEnabled;
51  import org.codehaus.plexus.util.IOUtil;
52  import org.codehaus.plexus.util.InterpolationFilterReader;
53  import org.codehaus.plexus.util.StringInputStream;
54  import org.codehaus.plexus.util.StringOutputStream;
55  import org.codehaus.plexus.util.StringUtils;
56  
57  /**
58   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
59   * @version $Id: JavaServiceWrapperDaemonGenerator.java 16492 2012-04-29 18:26:21Z khmarbaise $
60   * @plexus.component role-hint="jsw"
61   */
62  public class JavaServiceWrapperDaemonGenerator
63          extends AbstractLogEnabled
64          implements DaemonGenerator
65  {
66      private static final Map JSW_PLATFORMS_MAP = new HashMap ( ) {
67          {
68              put ( "linux-x86-32-lib", "lib/libwrapper-linux-x86-32.so" );
69              put ( "linux-x86-32-exec", "bin/wrapper-linux-x86-32" );
70              put ( "linux-x86-64-lib", "lib/libwrapper-linux-x86-64.so" );
71              put ( "linux-x86-64-exec", "bin/wrapper-linux-x86-64" );
72              put ( "linux-ppc-64-lib", "lib/libwrapper-linux-ppc-64.so" );
73              put ( "linux-ppc-64-exec", "bin/wrapper-linux-ppc-64" );
74              put ( "macosx-ppc-32-lib", "lib/libwrapper-macosx-ppc-32.jnilib" );
75              put ( "macosx-ppc-32-exec", "bin/wrapper-macosx-ppc-32" );
76              put ( "macosx-x86-universal-32-lib", "lib/libwrapper-macosx-universal-32.jnilib" );
77              put ( "macosx-x86-universal-32-exec", "bin/wrapper-macosx-universal-32" );
78              put ( "solaris-sparc-32-lib", "lib/libwrapper-solaris-sparc-32.so" );
79              put ( "solaris-sparc-32-exec", "bin/wrapper-solaris-sparc-32" );
80              put ( "solaris-sparc-64-lib", "lib/libwrapper-solaris-sparc-64.so" );
81              put ( "solaris-sparc-64-exec", "bin/wrapper-solaris-sparc-64" );
82              put ( "solaris-x86-32-lib", "lib/libwrapper-solaris-x86-32.so" );
83              put ( "solaris-x86-32-exec", "bin/wrapper-solaris-x86-32" );
84              put ( "windows-x86-32-lib", "lib/wrapper-windows-x86-32.dll" );
85              put ( "windows-x86-32-exec", "bin/wrapper-windows-x86-32.exe" );
86          }
87      };
88  
89      // -----------------------------------------------------------------------
90      // DaemonGenerator Implementation
91      // -----------------------------------------------------------------------
92  
93      public void generate ( DaemonGenerationRequest request )
94              throws DaemonGeneratorException
95      {
96          Daemon daemon = request.getDaemon ( );
97  
98          File outputDirectory = new File ( request.getOutputDirectory ( ), daemon.getId ( ) );
99  
100         Properties configuration = createConfiguration ( daemon );
101 
102         // Don't want these in the wrapper.conf file
103         String appBaseEnvVar = configuration.getProperty ( "app.base.envvar", "APP_BASE" );
104         configuration.remove ( "app.base.envvar" );
105         String runAsUserEnvVar = configuration.getProperty ( "run.as.user.envvar", "" );
106         if ( !runAsUserEnvVar.equals ( "" ) )
107         {
108             runAsUserEnvVar = "RUN_AS_USER=" + runAsUserEnvVar;
109             configuration.remove ( "run.as.user.envvar" );
110         }
111 
112         Properties context = createContext ( request, daemon );
113         context.setProperty ( "app.base.envvar", appBaseEnvVar );
114         context.setProperty ( "run.as.user.envvar", runAsUserEnvVar );
115 
116         writeWrapperConfFile ( request, daemon, outputDirectory, context, configuration );
117 
118         writeScriptFiles ( request, daemon, outputDirectory, context );
119 
120         List jswPlatformIncludes = getJswPlatformIncludes ( daemon );
121 
122         writeLibraryFiles ( outputDirectory, jswPlatformIncludes );
123 
124         writeExecutableFiles ( outputDirectory, jswPlatformIncludes );
125     }
126 
127     private void writeWrapperConfFile ( DaemonGenerationRequest request, Daemon daemon, File outputDirectory,
128             Properties context, Properties configuration )
129             throws DaemonGeneratorException
130     {
131         InputStream in = this.getClass ( ).getResourceAsStream ( "conf/wrapper.conf.in" );
132 
133         if ( in == null )
134         {
135             throw new DaemonGeneratorException ( "Could not load template." );
136         }
137 
138         FormattedProperties confFile = new FormattedProperties ( );
139 
140         try
141         {
142             confFile.read ( in );
143         }
144         catch ( IOException e )
145         {
146             throw new DaemonGeneratorException ( "Error reading template: " + e.getMessage ( ), e );
147         }
148         finally
149         {
150             IOUtil.close ( in );
151         }
152 
153         // TODO: configurable?
154         confFile.setPropertyAfter ( "wrapper.working.dir", "..", "wrapper.java.command" );
155         confFile.setProperty ( "wrapper.java.library.path.1", "lib" );
156 
157         confFile.setPropertyAfter ( "set.default.REPO_DIR", "lib", "wrapper.java.mainclass" );
158         confFile.setPropertyAfter ( "set.default." + context.getProperty ( "app.base.envvar" ), ".",
159                 "wrapper.java.mainclass" );
160 
161         if ( daemon.getWrapperLogFile ( ) == null )
162         {
163             // Write the default value to the wrapper.logfile.
164             confFile.setProperty ( "wrapper.logfile", "../logs/wrapper.log" );
165         }
166         else
167         {
168             confFile.setProperty ( "wrapper.logfile", daemon.getWrapperLogFile ( ) );
169         }
170 
171         if ( daemon.getJvmSettings ( ) != null
172                 && !StringUtils.isEmpty ( daemon.getJvmSettings ( ).getInitialMemorySize ( ) ) )
173         {
174             confFile.setProperty ( "wrapper.java.initmemory", daemon.getJvmSettings ( ).getInitialMemorySize ( ) );
175         }
176 
177         if ( daemon.getJvmSettings ( ) != null
178                 && !StringUtils.isEmpty ( daemon.getJvmSettings ( ).getMaxMemorySize ( ) ) )
179         {
180             confFile.setProperty ( "wrapper.java.maxmemory", daemon.getJvmSettings ( ).getMaxMemorySize ( ) );
181         }
182 
183         confFile.setProperty ( "wrapper.app.parameter.1", daemon.getMainClass ( ) );
184 
185         createClasspath ( request, confFile, configuration );
186         createAdditional ( daemon, confFile );
187         createParameters ( daemon, confFile );
188 
189         for ( Iterator i = configuration.entrySet ( ).iterator ( ); i.hasNext ( ); )
190         {
191             Map.Entry entry = ( Map.Entry ) i.next ( );
192 
193             String key = ( String ) entry.getKey ( );
194             String value = ( String ) entry.getValue ( );
195             if ( value.length ( ) > 0 )
196             {
197                 confFile.setProperty ( key, value );
198             }
199             else
200             {
201                 confFile.removeProperty ( key );
202             }
203         }
204 
205         StringOutputStream string = new StringOutputStream ( );
206         confFile.save ( string );
207 
208         Reader reader = new InputStreamReader ( new StringInputStream ( string.toString ( ) ) );
209 
210         writeFilteredFile ( request, daemon, reader, new File ( outputDirectory, "conf/wrapper.conf" ), context );
211     }
212 
213     private Properties createConfiguration ( Daemon daemon )
214     {
215         Properties configuration = new Properties ( );
216 
217         for ( Iterator i = daemon.getGeneratorConfigurations ( ).iterator ( ); i.hasNext ( ); )
218         {
219             GeneratorConfiguration generatorConfiguration = ( GeneratorConfiguration ) i.next ( );
220 
221             if ( generatorConfiguration.getGenerator ( ).equals ( "jsw" ) )
222             {
223                 configuration.putAll ( generatorConfiguration.getConfiguration ( ) );
224             }
225         }
226         return configuration;
227     }
228 
229     private static void writeFilteredFile ( DaemonGenerationRequest request, Daemon daemon, Reader reader,
230             File outputFile, Map context )
231             throws DaemonGeneratorException
232     {
233         InterpolationFilterReader interpolationFilterReader =
234                 new InterpolationFilterReader ( reader, context, "@", "@" );
235 
236         writeFile ( outputFile, interpolationFilterReader );
237     }
238 
239     private static Properties createContext ( DaemonGenerationRequest request, Daemon daemon )
240     {
241         Properties context = new Properties ( );
242         context.setProperty ( "app.long.name", request.getMavenProject ( ).getName ( ) );
243         context.setProperty ( "app.name", daemon.getId ( ) );
244         String description = request.getMavenProject ( ).getDescription ( );
245         if ( description == null )
246         {
247             description = request.getMavenProject ( ).getName ( );
248         }
249         context.setProperty ( "app.description", description );
250         return context;
251     }
252 
253     private static void writeFile ( File outputFile, Reader reader )
254             throws DaemonGeneratorException
255     {
256         FileWriter out = null;
257 
258         try
259         {
260             outputFile.getParentFile ( ).mkdirs ( );
261             out = new FileWriter ( outputFile );
262 
263             IOUtil.copy ( reader, out );
264         }
265         catch ( IOException e )
266         {
267             throw new DaemonGeneratorException ( "Error writing output file: " + outputFile.getAbsolutePath ( ), e );
268         }
269         finally
270         {
271             IOUtil.close ( reader );
272             IOUtil.close ( out );
273         }
274     }
275 
276     private static void writeFile ( File outputFile, InputStream inputStream )
277             throws DaemonGeneratorException
278     {
279         FileOutputStream out = null;
280 
281         try
282         {
283             outputFile.getParentFile ( ).mkdirs ( );
284             out = new FileOutputStream ( outputFile );
285 
286             IOUtil.copy ( inputStream, out );
287         }
288         catch ( IOException e )
289         {
290             throw new DaemonGeneratorException ( "Error writing output file: " + outputFile.getAbsolutePath ( ), e );
291         }
292         finally
293         {
294             IOUtil.close ( inputStream );
295             IOUtil.close ( out );
296         }
297     }
298 
299     private static void createClasspath ( DaemonGenerationRequest request, FormattedProperties confFile,
300             Properties configuration )
301     {
302         final String wrapperClassPathPrefix = "wrapper.java.classpath.";
303 
304         int counter = 1;
305         confFile.setProperty ( wrapperClassPathPrefix + counter++, "lib/wrapper.jar" );
306 
307         String configurationDirFirst = configuration.getProperty ( "configuration.directory.in.classpath.first" );
308         if ( configurationDirFirst != null )
309         {
310             confFile.setProperty ( wrapperClassPathPrefix + counter++, configurationDirFirst );
311         }
312 
313         MavenProject project = request.getMavenProject ( );
314         ArtifactRepositoryLayout layout = request.getRepositoryLayout ( );
315 
316         confFile.setProperty ( wrapperClassPathPrefix + counter++, "%REPO_DIR%/"
317                 + createDependency ( layout, project.getArtifact ( ) ).getRelativePath ( ) );
318 
319         Iterator j = project.getRuntimeArtifacts ( ).iterator ( );
320         while ( j.hasNext ( ) )
321         {
322             Artifact artifact = ( Artifact ) j.next ( );
323 
324             confFile.setProperty ( wrapperClassPathPrefix + counter, "%REPO_DIR%/"
325                     + createDependency ( layout, artifact ).getRelativePath ( ) );
326             counter++;
327         }
328 
329         String configurationDirLast = configuration.getProperty ( "configuration.directory.in.classpath.last" );
330         if ( configurationDirLast != null )
331         {
332             confFile.setProperty ( wrapperClassPathPrefix + counter++, configurationDirLast );
333         }
334     }
335 
336     private static Dependency createDependency ( ArtifactRepositoryLayout layout, Artifact artifact )
337     {
338         Dependency dependency = new Dependency ( );
339         dependency.setArtifactId ( artifact.getArtifactId ( ) );
340         dependency.setGroupId ( artifact.getGroupId ( ) );
341         dependency.setVersion ( artifact.getVersion ( ) );
342         dependency.setRelativePath ( layout.pathOf ( artifact ) );
343         return dependency;
344     }
345 
346     private static void createAdditional ( Daemon daemon, FormattedProperties confFile )
347     {
348         if ( daemon.getJvmSettings ( ) != null )
349         {
350             int count = 1;
351             for ( Iterator i = daemon.getJvmSettings ( ).getSystemProperties ( ).iterator ( ); i.hasNext ( ); count++ )
352             {
353                 String systemProperty = ( String ) i.next ( );
354                 confFile.setProperty ( "wrapper.java.additional." + count, "-D" + systemProperty );
355             }
356             for ( Iterator i = daemon.getJvmSettings ( ).getExtraArguments ( ).iterator ( ); i.hasNext ( ); count++ )
357             {
358                 String extraArgument = ( String ) i.next ( );
359                 confFile.setProperty ( "wrapper.java.additional." + count, extraArgument );
360             }
361         }
362     }
363 
364     private static void createParameters ( Daemon daemon, FormattedProperties confFile )
365     {
366         int count = 2;
367         for ( Iterator i = daemon.getCommandLineArguments ( ).iterator ( ); i.hasNext ( ); count++ )
368         {
369             String argument = ( String ) i.next ( );
370 
371             confFile.setProperty ( "wrapper.app.parameter." + count, argument );
372         }
373     }
374 
375     private void writeScriptFiles ( DaemonGenerationRequest request, Daemon daemon, File outputDirectory,
376             Properties context )
377             throws DaemonGeneratorException
378     {
379         // TODO: selectively depending on selected platforms instead of always doing both
380         InputStream shellScriptInputStream = this.getClass ( ).getResourceAsStream ( "bin/sh.script.in" );
381 
382         if ( shellScriptInputStream == null )
383         {
384             throw new DaemonGeneratorException ( "Could not load template." );
385         }
386 
387         Reader reader = new InputStreamReader ( shellScriptInputStream );
388 
389         writeFilteredFile ( request, daemon, reader, new File ( outputDirectory, "bin/" + daemon.getId ( ) ), context );
390 
391         // AppCommand.bat is not filtered
392         InputStream batchFileInputStream = this.getClass ( ).getResourceAsStream ( "bin/AppCommand.bat.in" );
393 
394         if ( batchFileInputStream == null )
395         {
396             throw new DaemonGeneratorException ( "Could not load template." );
397         }
398 
399         writeFile ( new File ( outputDirectory, "bin/" + daemon.getId ( ) + ".bat" ),
400                 batchFileInputStream );
401     }
402 
403     private void writeLibraryFiles ( File outputDirectory, List jswPlatformIncludes )
404             throws DaemonGeneratorException
405     {
406         copyResourceFile ( outputDirectory, "lib/wrapper.jar" );
407 
408         for ( Iterator iter = jswPlatformIncludes.iterator ( ); iter.hasNext ( ); )
409         {
410             String platform = ( String ) iter.next ( );
411             String libFile = ( String ) JSW_PLATFORMS_MAP.get ( platform + "-lib" );
412             if ( libFile != null )
413             {
414                 copyResourceFile ( outputDirectory, libFile );
415             }
416             else
417             {
418                 getLogger ( ).warn ( "Lib file for " + platform + " not found in map." );
419             }
420         }
421     }
422 
423     private void writeExecutableFiles ( File outputDirectory, List jswPlatformIncludes )
424             throws DaemonGeneratorException
425     {
426         for ( Iterator iter = jswPlatformIncludes.iterator ( ); iter.hasNext ( ); )
427         {
428             String platform = ( String ) iter.next ( );
429             String execFile = ( String ) JSW_PLATFORMS_MAP.get ( platform + "-exec" );
430             if ( execFile != null )
431             {
432                 copyResourceFile ( outputDirectory, execFile );
433             }
434             else
435             {
436                 getLogger ( ).warn ( "Exec file for " + platform + " not found in map." );
437             }
438         }
439     }
440 
441     private void copyResourceFile ( File outputDirectory, String fileName )
442             throws DaemonGeneratorException
443     {
444         InputStream batchFileInputStream = this.getClass ( ).getResourceAsStream ( fileName );
445 
446         if ( batchFileInputStream == null )
447         {
448             throw new DaemonGeneratorException ( "Could not load library file: " + fileName );
449         }
450 
451         writeFile ( new File ( outputDirectory, fileName ), batchFileInputStream );
452     }
453 
454     private List getJswPlatformIncludes ( Daemon daemon )
455     {
456         List jswPlatformIncludes = null;
457         for ( Iterator i = daemon.getGeneratorConfigurations ( ).iterator ( ); i.hasNext ( ); )
458         {
459             GeneratorConfiguration generatorConfiguration = ( GeneratorConfiguration ) i.next ( );
460 
461             if ( generatorConfiguration.getGenerator ( ).equals ( "jsw" ) )
462             {
463                 jswPlatformIncludes = generatorConfiguration.getIncludes ( );
464             }
465         }
466 
467         // set default if none is specified
468         if ( jswPlatformIncludes == null || jswPlatformIncludes.isEmpty ( ) )
469         {
470             jswPlatformIncludes = new ArrayList ( );
471             jswPlatformIncludes.add ( "linux-x86-32" );
472             jswPlatformIncludes.add ( "macosx-x86-universal-32" );
473             jswPlatformIncludes.add ( "solaris-x86-32" );
474             jswPlatformIncludes.add ( "windows-x86-32" );
475         }
476 
477         return jswPlatformIncludes;
478     }
479 }