package org.codehaus.mojo.appassembler.daemon.jsw; /* * The MIT License * * Copyright 2005-2007 The Codehaus. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; import org.apache.maven.project.MavenProject; import org.codehaus.mojo.appassembler.daemon.DaemonGenerationRequest; import org.codehaus.mojo.appassembler.daemon.DaemonGenerator; import org.codehaus.mojo.appassembler.daemon.DaemonGeneratorException; import org.codehaus.mojo.appassembler.model.*; import org.codehaus.mojo.appassembler.util.FormattedProperties; import org.codehaus.plexus.logging.AbstractLogEnabled; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.InterpolationFilterReader; import org.codehaus.plexus.util.StringInputStream; import org.codehaus.plexus.util.StringOutputStream; import org.codehaus.plexus.util.StringUtils; /** * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a> * @version $Id$ * @plexus.component role-hint="jsw" */ public class JavaServiceWrapperDaemonGenerator extends AbstractLogEnabled implements DaemonGenerator { private static final Map jswPlatformsMap = new HashMap() { { put( "linux-x86-32-lib", "lib/libwrapper-linux-x86-32.so" ); put( "linux-x86-32-exec", "bin/wrapper-linux-x86-32" ); put( "linux-x86-64-lib", "lib/libwrapper-linux-x86-64.so" ); put( "linux-x86-64-exec", "bin/wrapper-linux-x86-64" ); put( "linux-ppc-64-lib", "lib/libwrapper-linux-ppc-64.so" ); put( "linux-ppc-64-exec", "bin/wrapper-linux-ppc-64" ); put( "macosx-ppc-32-lib", "lib/libwrapper-macosx-ppc-32.jnilib" ); put( "macosx-ppc-32-exec", "bin/wrapper-macosx-ppc-32" ); put( "macosx-x86-universal-32-lib", "lib/libwrapper-macosx-universal-32.jnilib" ); put( "macosx-x86-universal-32-exec", "bin/wrapper-macosx-universal-32" ); put( "solaris-sparc-32-lib", "lib/libwrapper-solaris-sparc-32.so" ); put( "solaris-sparc-32-exec", "bin/wrapper-solaris-sparc-32" ); put( "solaris-sparc-64-lib", "lib/libwrapper-solaris-sparc-64.so" ); put( "solaris-sparc-64-exec", "bin/wrapper-solaris-sparc-64" ); put( "solaris-x86-32-lib", "lib/libwrapper-solaris-x86-32.so" ); put( "solaris-x86-32-exec", "bin/wrapper-solaris-x86-32" ); put( "windows-x86-32-lib", "lib/wrapper-windows-x86-32.dll" ); put( "windows-x86-32-exec", "bin/wrapper-windows-x86-32.exe" ); } }; // ----------------------------------------------------------------------- // DaemonGenerator Implementation // ----------------------------------------------------------------------- public void generate( DaemonGenerationRequest request ) throws DaemonGeneratorException { Daemon daemon = request.getDaemon(); File outputDirectory = new File( request.getOutputDirectory(), daemon.getId() ); Properties configuration = createConfiguration( daemon ); // Don't want these in the wrapper.conf file String appBaseEnvVar = configuration.getProperty( "app.base.envvar", "APP_BASE" ); configuration.remove( "app.base.envvar" ); String runAsUserEnvVar = configuration.getProperty( "run.as.user.envvar", "" ); if ( !runAsUserEnvVar.equals( "" ) ) { runAsUserEnvVar = "RUN_AS_USER=" + runAsUserEnvVar; configuration.remove( "run.as.user.envvar" ); } Properties context = createContext( request, daemon ); context.setProperty( "app.base.envvar", appBaseEnvVar ); context.setProperty( "run.as.user.envvar", runAsUserEnvVar ); writeWrapperConfFile( request, daemon, outputDirectory, context, configuration ); writeScriptFiles( request, daemon, outputDirectory, context ); List jswPlatformIncludes = getJswPlatformIncludes( daemon ); writeLibraryFiles( outputDirectory, jswPlatformIncludes ); writeExecutableFiles( outputDirectory, jswPlatformIncludes ); } private void writeWrapperConfFile( DaemonGenerationRequest request, Daemon daemon, File outputDirectory, Properties context, Properties configuration ) throws DaemonGeneratorException { InputStream in = this.getClass().getResourceAsStream( "conf/wrapper.conf.in" ); if ( in == null ) { throw new DaemonGeneratorException( "Could not load template." ); } FormattedProperties confFile = new FormattedProperties(); try { confFile.read( in ); } catch ( IOException e ) { throw new DaemonGeneratorException( "Error reading template: " + e.getMessage(), e ); } finally { IOUtil.close( in ); } // TODO: configurable? confFile.setPropertyAfter( "wrapper.working.dir", "..", "wrapper.java.command" ); confFile.setProperty( "wrapper.java.library.path.1", "lib" ); confFile.setPropertyAfter( "set.default.REPO_DIR", "repo", "wrapper.java.mainclass" ); confFile.setPropertyAfter( "set.default." + context.getProperty( "app.base.envvar" ), ".", "wrapper.java.mainclass" ); if ( daemon.getJvmSettings() != null && !StringUtils.isEmpty( daemon.getJvmSettings().getInitialMemorySize() ) ) { confFile.setProperty( "wrapper.java.initmemory", daemon.getJvmSettings().getInitialMemorySize() ); } if ( daemon.getJvmSettings() != null && !StringUtils.isEmpty( daemon.getJvmSettings().getMaxMemorySize() ) ) { confFile.setProperty( "wrapper.java.maxmemory", daemon.getJvmSettings().getMaxMemorySize() ); } confFile.setProperty( "wrapper.app.parameter.1", daemon.getMainClass() ); createClasspath( request, confFile, configuration ); createAdditional( daemon, confFile ); createParameters( daemon, confFile ); for ( Iterator i = configuration.entrySet().iterator(); i.hasNext(); ) { Map.Entry entry = (Map.Entry) i.next(); String key = (String) entry.getKey(); String value = (String) entry.getValue(); if ( value.length() > 0 ) { confFile.setProperty( key, value ); } else { confFile.removeProperty( key ); } } StringOutputStream string = new StringOutputStream(); confFile.save( string ); Reader reader = new InputStreamReader( new StringInputStream( string.toString() ) ); writeFilteredFile( request, daemon, reader, new File( outputDirectory, "conf/wrapper.conf" ), context ); } private Properties createConfiguration( Daemon daemon ) { Properties configuration = new Properties(); for ( Iterator i = daemon.getGeneratorConfigurations().iterator(); i.hasNext(); ) { GeneratorConfiguration generatorConfiguration = (GeneratorConfiguration) i.next(); if ( generatorConfiguration.getGenerator().equals( "jsw" ) ) { configuration.putAll( generatorConfiguration.getConfiguration() ); } } return configuration; } private static void writeFilteredFile( DaemonGenerationRequest request, Daemon daemon, Reader reader, File outputFile, Map context ) throws DaemonGeneratorException { InterpolationFilterReader interpolationFilterReader = new InterpolationFilterReader( reader, context, "@", "@" ); writeFile( outputFile, interpolationFilterReader ); } private static Properties createContext( DaemonGenerationRequest request, Daemon daemon ) { Properties context = new Properties(); context.setProperty( "app.long.name", request.getMavenProject().getName() ); context.setProperty( "app.name", daemon.getId() ); String description = request.getMavenProject().getDescription(); if ( description == null ) { description = request.getMavenProject().getName(); } context.setProperty( "app.description", description ); return context; } private static void writeFile( File outputFile, Reader reader ) throws DaemonGeneratorException { FileWriter out = null; try { outputFile.getParentFile().mkdirs(); out = new FileWriter( outputFile ); IOUtil.copy( reader, out ); } catch ( IOException e ) { throw new DaemonGeneratorException( "Error writing output file: " + outputFile.getAbsolutePath(), e ); } finally { IOUtil.close( reader ); IOUtil.close( out ); } } private static void writeFile( File outputFile, InputStream inputStream ) throws DaemonGeneratorException { FileOutputStream out = null; try { outputFile.getParentFile().mkdirs(); out = new FileOutputStream( outputFile ); IOUtil.copy( inputStream, out ); } catch ( IOException e ) { throw new DaemonGeneratorException( "Error writing output file: " + outputFile.getAbsolutePath(), e ); } finally { IOUtil.close( inputStream ); IOUtil.close( out ); } } private static void createClasspath( DaemonGenerationRequest request, FormattedProperties confFile, Properties configuration ) { final String wrapperClassPathPrefix = "wrapper.java.classpath."; int counter = 1; confFile.setProperty( wrapperClassPathPrefix + counter++, "lib/wrapper.jar" ); String configurationDirFirst = configuration.getProperty( "configuration.directory.in.classpath.first" ); if ( configurationDirFirst != null ) { confFile.setProperty( wrapperClassPathPrefix + counter++, configurationDirFirst ); } MavenProject project = request.getMavenProject(); ArtifactRepositoryLayout layout = request.getRepositoryLayout(); confFile.setProperty( wrapperClassPathPrefix + counter++, "%REPO_DIR%/" + createDependency( layout, project.getArtifact() ).getRelativePath() ); Iterator j = project.getRuntimeArtifacts().iterator(); while ( j.hasNext() ) { Artifact artifact = (Artifact) j.next(); confFile.setProperty( wrapperClassPathPrefix + counter, "%REPO_DIR%/" + createDependency( layout, artifact ).getRelativePath() ); counter++; } String configurationDirLast = configuration.getProperty( "configuration.directory.in.classpath.last" ); if ( configurationDirLast != null ) { confFile.setProperty( wrapperClassPathPrefix + counter++, configurationDirLast ); } } private static Dependency createDependency( ArtifactRepositoryLayout layout, Artifact artifact ) { Dependency dependency = new Dependency(); dependency.setArtifactId( artifact.getArtifactId() ); dependency.setGroupId( artifact.getGroupId() ); dependency.setVersion( artifact.getVersion() ); dependency.setRelativePath( layout.pathOf( artifact ) ); return dependency; } private static void createAdditional( Daemon daemon, FormattedProperties confFile ) { if ( daemon.getJvmSettings() != null ) { int count = 1; for ( Iterator i = daemon.getJvmSettings().getSystemProperties().iterator(); i.hasNext(); count++ ) { String systemProperty = (String) i.next(); confFile.setProperty( "wrapper.java.additional." + count, "-D" + systemProperty ); } for ( Iterator i = daemon.getJvmSettings().getExtraArguments().iterator(); i.hasNext(); count++ ) { String extraArgument = (String) i.next(); confFile.setProperty( "wrapper.java.additional." + count, extraArgument ); } } } private static void createParameters( Daemon daemon, FormattedProperties confFile ) { int count = 2; for ( Iterator i = daemon.getCommandLineArguments().iterator(); i.hasNext(); count++ ) { String argument = (String) i.next(); confFile.setProperty( "wrapper.app.parameter." + count, argument ); } } private void writeScriptFiles( DaemonGenerationRequest request, Daemon daemon, File outputDirectory, Properties context ) throws DaemonGeneratorException { // TODO: selectively depending on selected platforms instead of always doing both InputStream shellScriptInputStream = this.getClass().getResourceAsStream( "bin/sh.script.in" ); if ( shellScriptInputStream == null ) { throw new DaemonGeneratorException( "Could not load template." ); } Reader reader = new InputStreamReader( shellScriptInputStream ); writeFilteredFile( request, daemon, reader, new File( outputDirectory, "bin/" + daemon.getId() ), context ); // AppCommand.bat is not filtered InputStream batchFileInputStream = this.getClass().getResourceAsStream( "bin/AppCommand.bat.in" ); if ( batchFileInputStream == null ) { throw new DaemonGeneratorException( "Could not load template." ); } writeFile( new File( outputDirectory, "bin/" + daemon.getId() + ".bat" ), batchFileInputStream ); } private void writeLibraryFiles( File outputDirectory, List jswPlatformIncludes ) throws DaemonGeneratorException { copyResourceFile( outputDirectory, "lib/wrapper.jar" ); for ( Iterator iter = jswPlatformIncludes.iterator(); iter.hasNext(); ) { String platform = (String) iter.next(); String libFile = (String) jswPlatformsMap.get( platform + "-lib" ); if ( libFile != null ) { copyResourceFile( outputDirectory, libFile ); } else { getLogger().warn( "Lib file for " + platform + " not found in map." ); } } } private void writeExecutableFiles( File outputDirectory, List jswPlatformIncludes ) throws DaemonGeneratorException { for ( Iterator iter = jswPlatformIncludes.iterator(); iter.hasNext(); ) { String platform = (String) iter.next(); String execFile = (String) jswPlatformsMap.get( platform + "-exec" ); if ( execFile != null ) { copyResourceFile( outputDirectory, execFile ); } else { getLogger().warn( "Exec file for " + platform + " not found in map." ); } } } private void copyResourceFile( File outputDirectory, String fileName ) throws DaemonGeneratorException { InputStream batchFileInputStream = this.getClass().getResourceAsStream( fileName ); if ( batchFileInputStream == null ) { throw new DaemonGeneratorException( "Could not load library file: " + fileName ); } writeFile( new File( outputDirectory, fileName ), batchFileInputStream ); } private List getJswPlatformIncludes( Daemon daemon ) { List jswPlatformIncludes = null; for ( Iterator i = daemon.getGeneratorConfigurations().iterator(); i.hasNext(); ) { GeneratorConfiguration generatorConfiguration = (GeneratorConfiguration) i.next(); if ( generatorConfiguration.getGenerator().equals( "jsw" ) ) { jswPlatformIncludes = generatorConfiguration.getIncludes(); } } // set default if none is specified if ( jswPlatformIncludes == null || jswPlatformIncludes.isEmpty() ) { jswPlatformIncludes = new ArrayList(); jswPlatformIncludes.add( "linux-x86-32" ); jswPlatformIncludes.add( "macosx-x86-universal-32" ); jswPlatformIncludes.add( "solaris-x86-32" ); jswPlatformIncludes.add( "windows-x86-32" ); } return jswPlatformIncludes; } }