1 package org.apache.tomcat.maven.plugin.tomcat7.run; 2 /* 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 */ 20 21 import org.apache.commons.compress.archivers.ArchiveException; 22 import org.apache.commons.compress.archivers.ArchiveOutputStream; 23 import org.apache.commons.compress.archivers.ArchiveStreamFactory; 24 import org.apache.commons.compress.archivers.jar.JarArchiveEntry; 25 import org.apache.commons.io.IOUtils; 26 import org.apache.commons.lang.StringUtils; 27 import org.apache.maven.artifact.Artifact; 28 import org.apache.maven.artifact.resolver.ArtifactNotFoundException; 29 import org.apache.maven.artifact.resolver.ArtifactResolutionException; 30 import org.apache.maven.model.Dependency; 31 import org.apache.maven.plugin.MojoExecutionException; 32 import org.apache.maven.plugin.MojoFailureException; 33 import org.apache.maven.plugins.annotations.Parameter; 34 import org.apache.tomcat.maven.runner.Tomcat7Runner; 35 import org.apache.tomcat.maven.runner.Tomcat7RunnerCli; 36 import org.codehaus.plexus.archiver.jar.Manifest; 37 import org.codehaus.plexus.archiver.jar.ManifestException; 38 import org.codehaus.plexus.util.DirectoryScanner; 39 40 import java.io.File; 41 import java.io.FileInputStream; 42 import java.io.FileOutputStream; 43 import java.io.IOException; 44 import java.io.PrintWriter; 45 import java.util.Properties; 46 import java.util.jar.JarFile; 47 48 /** 49 * Abstract Mojo for building deployable and executable war files 50 * 51 * @since 2.1 52 */ 53 public abstract class AbstractStandaloneWarMojo 54 extends AbstractExecWarMojo 55 { 56 57 /** 58 * Name of the generated WAR. 59 */ 60 @Parameter(property = "tomcat.jar.finalName", 61 defaultValue = "${project.artifactId}-${project.version}-standalone.war", required = true) 62 protected String finalName; 63 64 /** 65 * the classifier to use for the attached/generated artifact 66 */ 67 @Parameter(property = "maven.tomcat.exec.war.attachArtifactClassifier", defaultValue = "standalone", 68 required = true) 69 protected String attachArtifactClassifier; 70 71 /** 72 * the type to use for the attached/generated artifact 73 * 74 * @since 2.2 75 */ 76 @Parameter(property = "maven.tomcat.exec.war.attachArtifactType", defaultValue = "war", required = true) 77 protected String attachArtifactClassifierType; 78 79 public void execute() 80 throws MojoExecutionException, MojoFailureException 81 { 82 if ( !"war".equals( project.getPackaging() ) ) 83 { 84 throw new MojoFailureException( "Pacakaging must be of type war for standalone-war goal." ); 85 } 86 87 File warExecFile = new File( buildDirectory, finalName ); 88 if ( warExecFile.exists() ) 89 { 90 warExecFile.delete(); 91 } 92 93 File execWarJar = new File( buildDirectory, finalName ); 94 95 FileOutputStream execWarJarOutputStream = null; 96 ArchiveOutputStream os = null; 97 File tmpPropertiesFile = null; 98 File tmpManifestFile = null; 99 FileOutputStream tmpPropertiesFileOutputStream = null; 100 PrintWriter tmpManifestWriter = null; 101 102 try 103 { 104 tmpPropertiesFile = new File( buildDirectory, "war-exec.properties" ); 105 if ( tmpPropertiesFile.exists() ) 106 { 107 tmpPropertiesFile.delete(); 108 } 109 tmpPropertiesFile.getParentFile().mkdirs(); 110 111 tmpManifestFile = new File( buildDirectory, "war-exec.manifest" ); 112 if ( tmpManifestFile.exists() ) 113 { 114 tmpManifestFile.delete(); 115 } 116 tmpPropertiesFileOutputStream = new FileOutputStream( tmpPropertiesFile ); 117 execWarJar.getParentFile().mkdirs(); 118 execWarJar.createNewFile(); 119 execWarJarOutputStream = new FileOutputStream( execWarJar ); 120 121 tmpManifestWriter = new PrintWriter( tmpManifestFile ); 122 123 // store : 124 //* wars in the root: foo.war 125 //* tomcat jars 126 //* file tomcat.standalone.properties with possible values : 127 // * useServerXml=true/false to use directly the one provided 128 // * enableNaming=true/false 129 // * wars=foo.war|contextpath;bar.war ( |contextpath is optionnal if empty use the war name ) 130 // * accessLogValveFormat= 131 // * connectorhttpProtocol: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol 132 // * codeSourceContextPath=path parameter, default is project.artifactId 133 //* optionnal: conf/ with usual tomcat configuration files 134 //* MANIFEST with Main-Class 135 136 Properties properties = new Properties(); 137 138 properties.put( Tomcat7Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY, 139 Long.toString( System.currentTimeMillis() ) ); 140 properties.put( Tomcat7Runner.ENABLE_NAMING_KEY, Boolean.toString( enableNaming ) ); 141 properties.put( Tomcat7Runner.ACCESS_LOG_VALVE_FORMAT_KEY, accessLogValveFormat ); 142 properties.put( Tomcat7Runner.HTTP_PROTOCOL_KEY, connectorHttpProtocol ); 143 properties.put( Tomcat7Runner.CODE_SOURCE_CONTEXT_PATH, path ); 144 145 os = new ArchiveStreamFactory().createArchiveOutputStream( ArchiveStreamFactory.JAR, 146 execWarJarOutputStream ); 147 148 extractJarToArchive( new JarFile( projectArtifact.getFile() ), os, null ); 149 150 if ( serverXml != null && serverXml.exists() ) 151 { 152 os.putArchiveEntry( new JarArchiveEntry( "conf/server.xml" ) ); 153 IOUtils.copy( new FileInputStream( serverXml ), os ); 154 os.closeArchiveEntry(); 155 properties.put( Tomcat7Runner.USE_SERVER_XML_KEY, Boolean.TRUE.toString() ); 156 } 157 else 158 { 159 properties.put( Tomcat7Runner.USE_SERVER_XML_KEY, Boolean.FALSE.toString() ); 160 } 161 162 os.putArchiveEntry( new JarArchiveEntry( "conf/web.xml" ) ); 163 IOUtils.copy( getClass().getResourceAsStream( "/conf/web.xml" ), os ); 164 os.closeArchiveEntry(); 165 166 properties.store( tmpPropertiesFileOutputStream, "created by Apache Tomcat Maven plugin" ); 167 168 tmpPropertiesFileOutputStream.flush(); 169 tmpPropertiesFileOutputStream.close(); 170 171 os.putArchiveEntry( new JarArchiveEntry( Tomcat7RunnerCli.STAND_ALONE_PROPERTIES_FILENAME ) ); 172 IOUtils.copy( new FileInputStream( tmpPropertiesFile ), os ); 173 os.closeArchiveEntry(); 174 175 // add tomcat classes 176 for ( Artifact pluginArtifact : pluginArtifacts ) 177 { 178 if ( StringUtils.equals( "org.apache.tomcat", pluginArtifact.getGroupId() ) || StringUtils.equals( 179 "org.apache.tomcat.embed", pluginArtifact.getGroupId() ) || StringUtils.equals( 180 "org.eclipse.jdt.core.compiler", pluginArtifact.getGroupId() ) || StringUtils.equals( "commons-cli", 181 pluginArtifact.getArtifactId() ) 182 || StringUtils.equals( "tomcat7-war-runner", pluginArtifact.getArtifactId() ) ) 183 { 184 JarFile jarFile = new JarFile( pluginArtifact.getFile() ); 185 extractJarToArchive( jarFile, os, null ); 186 } 187 } 188 189 // add extra dependencies 190 if ( extraDependencies != null && !extraDependencies.isEmpty() ) 191 { 192 for ( Dependency dependency : extraDependencies ) 193 { 194 String version = dependency.getVersion(); 195 if ( StringUtils.isEmpty( version ) ) 196 { 197 version = findArtifactVersion( dependency ); 198 } 199 200 if ( StringUtils.isEmpty( version ) ) 201 { 202 throw new MojoExecutionException( 203 "Dependency '" + dependency.getGroupId() + "':'" + dependency.getArtifactId() 204 + "' does not have version specified" ); 205 } 206 // String groupId, String artifactId, String version, String scope, String type 207 Artifact artifact = 208 artifactFactory.createArtifact( dependency.getGroupId(), dependency.getArtifactId(), version, 209 dependency.getScope(), dependency.getType() ); 210 211 artifactResolver.resolve( artifact, this.remoteRepos, this.local ); 212 JarFile jarFile = new JarFile( artifact.getFile() ); 213 extractJarToArchive( jarFile, os, excludes ); 214 } 215 } 216 217 Manifest manifest = new Manifest(); 218 219 Manifest.Attribute mainClassAtt = new Manifest.Attribute(); 220 mainClassAtt.setName( "Main-Class" ); 221 mainClassAtt.setValue( mainClass ); 222 manifest.addConfiguredAttribute( mainClassAtt ); 223 224 manifest.write( tmpManifestWriter ); 225 tmpManifestWriter.flush(); 226 tmpManifestWriter.close(); 227 228 os.putArchiveEntry( new JarArchiveEntry( "META-INF/MANIFEST.MF" ) ); 229 IOUtils.copy( new FileInputStream( tmpManifestFile ), os ); 230 os.closeArchiveEntry(); 231 232 if ( attachArtifact ) 233 { 234 //MavenProject project, String artifactType, String artifactClassifier, File artifactFile 235 projectHelper.attachArtifact( project, attachArtifactClassifierType, attachArtifactClassifier, 236 execWarJar ); 237 } 238 239 if ( extraResources != null ) 240 { 241 for ( ExtraResource extraResource : extraResources ) 242 { 243 244 DirectoryScanner directoryScanner = new DirectoryScanner(); 245 directoryScanner.setBasedir( extraResource.getDirectory() ); 246 directoryScanner.addDefaultExcludes(); 247 directoryScanner.setExcludes( toStringArray( extraResource.getExcludes() ) ); 248 directoryScanner.setIncludes( toStringArray( extraResource.getIncludes() ) ); 249 directoryScanner.scan(); 250 for ( String includeFile : directoryScanner.getIncludedFiles() ) 251 { 252 getLog().debug( "include file:" + includeFile ); 253 os.putArchiveEntry( new JarArchiveEntry( includeFile ) ); 254 IOUtils.copy( new FileInputStream( new File( extraResource.getDirectory(), includeFile ) ), 255 os ); 256 os.closeArchiveEntry(); 257 } 258 } 259 } 260 261 if ( tomcatConfigurationFilesDirectory != null && tomcatConfigurationFilesDirectory.exists() ) 262 { 263 // Because its the tomcat default dir for configs 264 String aConfigOutputDir = "conf/"; 265 copyDirectoryContentIntoArchive( tomcatConfigurationFilesDirectory, aConfigOutputDir, os ); 266 } 267 } 268 catch ( ManifestException e ) 269 { 270 throw new MojoExecutionException( e.getMessage(), e ); 271 } 272 catch ( IOException e ) 273 { 274 throw new MojoExecutionException( e.getMessage(), e ); 275 } 276 catch ( ArchiveException e ) 277 { 278 throw new MojoExecutionException( e.getMessage(), e ); 279 } 280 catch ( ArtifactNotFoundException e ) 281 { 282 throw new MojoExecutionException( e.getMessage(), e ); 283 } 284 catch ( ArtifactResolutionException e ) 285 { 286 throw new MojoExecutionException( e.getMessage(), e ); 287 } 288 finally 289 { 290 IOUtils.closeQuietly( os ); 291 IOUtils.closeQuietly( tmpManifestWriter ); 292 IOUtils.closeQuietly( execWarJarOutputStream ); 293 IOUtils.closeQuietly( tmpPropertiesFileOutputStream ); 294 } 295 296 } 297 }