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.FileUtils; 26 import org.apache.commons.io.IOUtils; 27 import org.apache.commons.lang.StringUtils; 28 import org.apache.maven.artifact.Artifact; 29 import org.apache.maven.artifact.factory.ArtifactFactory; 30 import org.apache.maven.artifact.repository.ArtifactRepository; 31 import org.apache.maven.artifact.resolver.ArtifactNotFoundException; 32 import org.apache.maven.artifact.resolver.ArtifactResolutionException; 33 import org.apache.maven.artifact.resolver.ArtifactResolver; 34 import org.apache.maven.model.Dependency; 35 import org.apache.maven.plugin.MojoExecutionException; 36 import org.apache.maven.plugin.MojoFailureException; 37 import org.apache.maven.plugins.annotations.Component; 38 import org.apache.maven.plugins.annotations.Parameter; 39 import org.apache.maven.project.MavenProject; 40 import org.apache.maven.project.MavenProjectHelper; 41 import org.apache.tomcat.maven.plugin.tomcat7.AbstractTomcat7Mojo; 42 import org.apache.tomcat.maven.runner.Tomcat7Runner; 43 import org.apache.tomcat.maven.runner.Tomcat7RunnerCli; 44 import org.codehaus.plexus.archiver.jar.Manifest; 45 import org.codehaus.plexus.archiver.jar.ManifestException; 46 import org.codehaus.plexus.util.DirectoryScanner; 47 import org.codehaus.plexus.util.SelectorUtils; 48 49 import java.io.File; 50 import java.io.FileInputStream; 51 import java.io.FileOutputStream; 52 import java.io.IOException; 53 import java.io.OutputStream; 54 import java.io.PrintWriter; 55 import java.util.ArrayList; 56 import java.util.Enumeration; 57 import java.util.Iterator; 58 import java.util.List; 59 import java.util.Properties; 60 import java.util.jar.JarEntry; 61 import java.util.jar.JarFile; 62 63 /** 64 * @author Olivier Lamy 65 * @since 2.0 66 */ 67 public abstract class AbstractExecWarMojo 68 extends AbstractTomcat7Mojo 69 { 70 71 @Parameter( defaultValue = "${project.artifact}", required = true, readonly = true ) 72 protected Artifact projectArtifact; 73 74 /** 75 * The maven project. 76 */ 77 @Parameter( defaultValue = "${project}", required = true, readonly = true ) 78 protected MavenProject project; 79 80 @Parameter( defaultValue = "${plugin.artifacts}", required = true ) 81 protected List<Artifact> pluginArtifacts; 82 83 @Parameter( defaultValue = "${project.build.directory}" ) 84 protected File buildDirectory; 85 86 /** 87 * Path under {@link #buildDirectory} where this mojo may do temporary work. 88 */ 89 @Parameter( defaultValue = "${project.build.directory}/tomcat7-maven-plugin-exec" ) 90 private File pluginWorkDirectory; 91 92 @Parameter( property = "maven.tomcat.exec.war.tomcatConf", defaultValue = "src/main/tomcatconf" ) 93 protected File tomcatConfigurationFilesDirectory; 94 95 @Parameter( defaultValue = "src/main/tomcatconf/server.xml", property = "maven.tomcat.exec.war.serverXml" ) 96 protected File serverXml; 97 98 /** 99 * Name of the generated exec JAR. 100 */ 101 @Parameter( property = "tomcat.jar.finalName", 102 defaultValue = "${project.artifactId}-${project.version}-war-exec.jar", required = true ) 103 protected String finalName; 104 105 /** 106 * Skip the execution 107 * 108 * @since 2.2 109 */ 110 @Parameter( property = "maven.tomcat.skip", defaultValue = "false" ) 111 private boolean skip; 112 113 /** 114 * The webapp context path to use for the web application being run. 115 * The name to store webapp in exec jar. Do not use / 116 */ 117 @Parameter( property = "maven.tomcat.path", defaultValue = "${project.artifactId}", required = true ) 118 protected String path; 119 120 @Parameter 121 protected List<WarRunDependency> warRunDependencies; 122 123 @Component 124 protected ArtifactResolver artifactResolver; 125 126 /** 127 * Maven Artifact Factory component. 128 */ 129 @Component 130 protected ArtifactFactory artifactFactory; 131 132 /** 133 * Location of the local repository. 134 */ 135 @Parameter( defaultValue = "${localRepository}", required = true, readonly = true ) 136 protected ArtifactRepository local; 137 138 /** 139 * List of Remote Repositories used by the resolver 140 */ 141 @Parameter( defaultValue = "${project.remoteArtifactRepositories}", required = true, readonly = true ) 142 protected List<ArtifactRepository> remoteRepos; 143 144 @Component 145 protected MavenProjectHelper projectHelper; 146 147 /** 148 * Attach or not the generated artifact to the build (use true if you want to install or deploy it) 149 */ 150 @Parameter( property = "maven.tomcat.exec.war.attachArtifact", defaultValue = "true", required = true ) 151 protected boolean attachArtifact; 152 153 154 /** 155 * the classifier to use for the attached/generated artifact 156 */ 157 @Parameter( property = "maven.tomcat.exec.war.attachArtifactClassifier", defaultValue = "exec-war", 158 required = true ) 159 protected String attachArtifactClassifier; 160 161 162 /** 163 * the type to use for the attached/generated artifact 164 */ 165 @Parameter( property = "maven.tomcat.exec.war.attachArtifactType", defaultValue = "jar", required = true ) 166 protected String attachArtifactClassifierType; 167 168 /** 169 * to enable naming when starting tomcat 170 */ 171 @Parameter( property = "maven.tomcat.exec.war.enableNaming", defaultValue = "false", required = true ) 172 protected boolean enableNaming; 173 174 /** 175 * see http://tomcat.apache.org/tomcat-7.0-doc/config/valve.html 176 */ 177 @Parameter( property = "maven.tomcat.exec.war.accessLogValveFormat", defaultValue = "%h %l %u %t %r %s %b %I %D", 178 required = true ) 179 protected String accessLogValveFormat; 180 181 /** 182 * list of extra dependencies to add in the standalone tomcat jar: your jdbc driver, mail.jar etc.. 183 * <b>Those dependencies will be in root classloader.</b> 184 */ 185 @Parameter 186 protected List<ExtraDependency> extraDependencies; 187 188 /** 189 * list of extra resources to add in the standalone tomcat jar: your logger configuration etc 190 */ 191 @Parameter 192 protected List<ExtraResource> extraResources; 193 194 /** 195 * Main class to use for starting the standalone jar. 196 */ 197 @Parameter( property = "maven.tomcat.exec.war.mainClass", 198 defaultValue = "org.apache.tomcat.maven.runner.Tomcat7RunnerCli", required = true ) 199 protected String mainClass; 200 201 /** 202 * which connector protocol to use HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol 203 */ 204 @Parameter( property = "maven.tomcat.exec.war.connectorHttpProtocol", defaultValue = "HTTP/1.1", required = true ) 205 protected String connectorHttpProtocol; 206 207 /** 208 * configure a default http port for the standalone jar 209 * 210 * @since 2.2 211 */ 212 @Parameter( property = "maven.tomcat.exec.war.httpPort" ) 213 protected String httpPort; 214 215 /** 216 * File patterns to exclude from extraDependencies 217 * 218 * @since 2.2 219 */ 220 @Parameter 221 protected String[] excludes; 222 223 public void execute() 224 throws MojoExecutionException, MojoFailureException 225 { 226 if ( this.skip ) 227 { 228 getLog().info( "skip execution" ); 229 return; 230 } 231 //project.addAttachedArtifact( ); 232 File warExecFile = new File( buildDirectory, finalName ); 233 if ( warExecFile.exists() ) 234 { 235 warExecFile.delete(); 236 } 237 238 File execWarJar = new File( buildDirectory, finalName ); 239 240 FileOutputStream execWarJarOutputStream = null; 241 ArchiveOutputStream os = null; 242 File tmpPropertiesFile = null; 243 File tmpManifestFile = null; 244 FileOutputStream tmpPropertiesFileOutputStream = null; 245 PrintWriter tmpManifestWriter = null; 246 247 try 248 { 249 250 tmpPropertiesFile = new File( buildDirectory, "war-exec.properties" ); 251 if ( tmpPropertiesFile.exists() ) 252 { 253 tmpPropertiesFile.delete(); 254 } 255 tmpPropertiesFile.getParentFile().mkdirs(); 256 257 tmpManifestFile = new File( buildDirectory, "war-exec.manifest" ); 258 if ( tmpManifestFile.exists() ) 259 { 260 tmpManifestFile.delete(); 261 } 262 tmpPropertiesFileOutputStream = new FileOutputStream( tmpPropertiesFile ); 263 execWarJar.getParentFile().mkdirs(); 264 execWarJar.createNewFile(); 265 execWarJarOutputStream = new FileOutputStream( execWarJar ); 266 267 tmpManifestWriter = new PrintWriter( tmpManifestFile ); 268 269 // store : 270 //* wars in the root: foo.war 271 //* tomcat jars 272 //* file tomcat.standalone.properties with possible values : 273 // * useServerXml=true/false to use directly the one provided 274 // * enableNaming=true/false 275 // * wars=foo.war|contextpath;bar.war ( |contextpath is optionnal if empty use the war name ) 276 // * accessLogValveFormat= 277 // * connectorhttpProtocol: HTTP/1.1 or org.apache.coyote.http11.Http11NioProtocol 278 //* optionnal: conf/ with usual tomcat configuration files 279 //* MANIFEST with Main-Class 280 281 Properties properties = new Properties(); 282 283 properties.put( Tomcat7Runner.ARCHIVE_GENERATION_TIMESTAMP_KEY, 284 Long.toString( System.currentTimeMillis() ) ); 285 properties.put( Tomcat7Runner.ENABLE_NAMING_KEY, Boolean.toString( enableNaming ) ); 286 properties.put( Tomcat7Runner.ACCESS_LOG_VALVE_FORMAT_KEY, accessLogValveFormat ); 287 properties.put( Tomcat7Runner.HTTP_PROTOCOL_KEY, connectorHttpProtocol ); 288 289 if ( httpPort != null ) 290 { 291 properties.put( Tomcat7Runner.HTTP_PORT_KEY, httpPort ); 292 } 293 294 os = new ArchiveStreamFactory().createArchiveOutputStream( ArchiveStreamFactory.JAR, 295 execWarJarOutputStream ); 296 297 if ( "war".equals( project.getPackaging() ) ) 298 { 299 300 os.putArchiveEntry( new JarArchiveEntry( StringUtils.removeStart( path, "/" ) + ".war" ) ); 301 IOUtils.copy( new FileInputStream( projectArtifact.getFile() ), os ); 302 os.closeArchiveEntry(); 303 304 properties.put( Tomcat7Runner.WARS_KEY, StringUtils.removeStart( path, "/" ) + ".war|" + path ); 305 } 306 else if ( warRunDependencies != null && !warRunDependencies.isEmpty() ) 307 { 308 for ( WarRunDependency warRunDependency : warRunDependencies ) 309 { 310 if ( warRunDependency.dependency != null ) 311 { 312 Dependency dependency = warRunDependency.dependency; 313 String version = dependency.getVersion(); 314 if ( StringUtils.isEmpty( version ) ) 315 { 316 version = findArtifactVersion( dependency ); 317 } 318 319 if ( StringUtils.isEmpty( version ) ) 320 { 321 throw new MojoExecutionException( 322 "Dependency '" + dependency.getGroupId() + "':'" + dependency.getArtifactId() 323 + "' does not have version specified" ); 324 } 325 Artifact artifact = artifactFactory.createArtifactWithClassifier( dependency.getGroupId(), 326 dependency.getArtifactId(), 327 version, 328 dependency.getType(), 329 dependency.getClassifier() ); 330 331 artifactResolver.resolve( artifact, this.remoteRepos, this.local ); 332 333 File warFileToBundle = new File( resolvePluginWorkDir(), artifact.getFile().getName() ); 334 FileUtils.copyFile( artifact.getFile(), warFileToBundle ); 335 336 if ( warRunDependency.contextXml != null ) 337 { 338 warFileToBundle = addContextXmlToWar( warRunDependency.contextXml, warFileToBundle ); 339 } 340 final String warFileName = artifact.getFile().getName(); 341 os.putArchiveEntry( new JarArchiveEntry( warFileName ) ); 342 IOUtils.copy( new FileInputStream( warFileToBundle ), os ); 343 os.closeArchiveEntry(); 344 String propertyWarValue = properties.getProperty( Tomcat7Runner.WARS_KEY ); 345 String contextPath = 346 StringUtils.isEmpty( warRunDependency.contextPath ) ? "/" : warRunDependency.contextPath; 347 if ( propertyWarValue != null ) 348 { 349 properties.put( Tomcat7Runner.WARS_KEY, 350 propertyWarValue + ";" + warFileName + "|" + contextPath ); 351 } 352 else 353 { 354 properties.put( Tomcat7Runner.WARS_KEY, warFileName + "|" + contextPath ); 355 } 356 } 357 } 358 } 359 360 if ( serverXml != null && serverXml.exists() ) 361 { 362 os.putArchiveEntry( new JarArchiveEntry( "conf/server.xml" ) ); 363 IOUtils.copy( new FileInputStream( serverXml ), os ); 364 os.closeArchiveEntry(); 365 properties.put( Tomcat7Runner.USE_SERVER_XML_KEY, Boolean.TRUE.toString() ); 366 } 367 else 368 { 369 properties.put( Tomcat7Runner.USE_SERVER_XML_KEY, Boolean.FALSE.toString() ); 370 } 371 372 os.putArchiveEntry( new JarArchiveEntry( "conf/web.xml" ) ); 373 IOUtils.copy( getClass().getResourceAsStream( "/conf/web.xml" ), os ); 374 os.closeArchiveEntry(); 375 376 properties.store( tmpPropertiesFileOutputStream, "created by Apache Tomcat Maven plugin" ); 377 378 tmpPropertiesFileOutputStream.flush(); 379 tmpPropertiesFileOutputStream.close(); 380 381 os.putArchiveEntry( new JarArchiveEntry( Tomcat7RunnerCli.STAND_ALONE_PROPERTIES_FILENAME ) ); 382 IOUtils.copy( new FileInputStream( tmpPropertiesFile ), os ); 383 os.closeArchiveEntry(); 384 385 // add tomcat classes 386 for ( Artifact pluginArtifact : pluginArtifacts ) 387 { 388 if ( StringUtils.equals( "org.apache.tomcat", pluginArtifact.getGroupId() ) || StringUtils.equals( 389 "org.apache.tomcat.embed", pluginArtifact.getGroupId() ) || StringUtils.equals( 390 "org.eclipse.jdt.core.compiler", pluginArtifact.getGroupId() ) || StringUtils.equals( "commons-cli", 391 pluginArtifact.getArtifactId() ) 392 || StringUtils.equals( "tomcat7-war-runner", pluginArtifact.getArtifactId() ) ) 393 { 394 JarFile jarFile = new JarFile( pluginArtifact.getFile() ); 395 extractJarToArchive( jarFile, os, null ); 396 } 397 } 398 399 // add extra dependencies 400 if ( extraDependencies != null && !extraDependencies.isEmpty() ) 401 { 402 for ( Dependency dependency : extraDependencies ) 403 { 404 String version = dependency.getVersion(); 405 if ( StringUtils.isEmpty( version ) ) 406 { 407 version = findArtifactVersion( dependency ); 408 } 409 410 if ( StringUtils.isEmpty( version ) ) 411 { 412 throw new MojoExecutionException( 413 "Dependency '" + dependency.getGroupId() + "':'" + dependency.getArtifactId() 414 + "' does not have version specified" ); 415 } 416 417 // String groupId, String artifactId, String version, String scope, String type 418 Artifact artifact = 419 artifactFactory.createArtifact( dependency.getGroupId(), dependency.getArtifactId(), version, 420 dependency.getScope(), dependency.getType() ); 421 422 artifactResolver.resolve( artifact, this.remoteRepos, this.local ); 423 JarFile jarFile = new JarFile( artifact.getFile() ); 424 extractJarToArchive( jarFile, os, this.excludes ); 425 } 426 } 427 428 Manifest manifest = new Manifest(); 429 430 Manifest.Attribute mainClassAtt = new Manifest.Attribute(); 431 mainClassAtt.setName( "Main-Class" ); 432 mainClassAtt.setValue( mainClass ); 433 manifest.addConfiguredAttribute( mainClassAtt ); 434 435 manifest.write( tmpManifestWriter ); 436 tmpManifestWriter.flush(); 437 tmpManifestWriter.close(); 438 439 os.putArchiveEntry( new JarArchiveEntry( "META-INF/MANIFEST.MF" ) ); 440 IOUtils.copy( new FileInputStream( tmpManifestFile ), os ); 441 os.closeArchiveEntry(); 442 443 if ( attachArtifact ) 444 { 445 //MavenProject project, String artifactType, String artifactClassifier, File artifactFile 446 projectHelper.attachArtifact( project, attachArtifactClassifierType, attachArtifactClassifier, 447 execWarJar ); 448 } 449 450 if ( extraResources != null ) 451 { 452 for ( ExtraResource extraResource : extraResources ) 453 { 454 455 DirectoryScanner directoryScanner = new DirectoryScanner(); 456 directoryScanner.setBasedir( extraResource.getDirectory() ); 457 directoryScanner.addDefaultExcludes(); 458 directoryScanner.setExcludes( toStringArray( extraResource.getExcludes() ) ); 459 directoryScanner.setIncludes( toStringArray( extraResource.getIncludes() ) ); 460 directoryScanner.scan(); 461 for ( String includeFile : directoryScanner.getIncludedFiles() ) 462 { 463 getLog().debug( "include file:" + includeFile ); 464 os.putArchiveEntry( new JarArchiveEntry( includeFile ) ); 465 IOUtils.copy( new FileInputStream( new File( extraResource.getDirectory(), includeFile ) ), 466 os ); 467 os.closeArchiveEntry(); 468 } 469 } 470 } 471 472 if ( tomcatConfigurationFilesDirectory != null && tomcatConfigurationFilesDirectory.exists() ) 473 { 474 // Because its the tomcat default dir for configs 475 String aConfigOutputDir = "conf/"; 476 copyDirectoryContentIntoArchive( tomcatConfigurationFilesDirectory, aConfigOutputDir, os ); 477 } 478 479 } 480 catch ( ManifestException e ) 481 { 482 throw new MojoExecutionException( e.getMessage(), e ); 483 } 484 catch ( IOException e ) 485 { 486 throw new MojoExecutionException( e.getMessage(), e ); 487 } 488 catch ( ArchiveException e ) 489 { 490 throw new MojoExecutionException( e.getMessage(), e ); 491 } 492 catch ( ArtifactNotFoundException e ) 493 { 494 throw new MojoExecutionException( e.getMessage(), e ); 495 } 496 catch ( ArtifactResolutionException e ) 497 { 498 throw new MojoExecutionException( e.getMessage(), e ); 499 } 500 finally 501 { 502 IOUtils.closeQuietly( os ); 503 IOUtils.closeQuietly( tmpManifestWriter ); 504 IOUtils.closeQuietly( execWarJarOutputStream ); 505 IOUtils.closeQuietly( tmpPropertiesFileOutputStream ); 506 } 507 } 508 509 protected String findArtifactVersion( Dependency dependency ) 510 { 511 // search in project.dependencies 512 for ( Dependency projectDependency : (List<Dependency>) this.project.getDependencies() ) 513 { 514 if ( sameDependencyWithoutVersion( dependency, projectDependency ) ) 515 { 516 return projectDependency.getVersion(); 517 } 518 } 519 520 // search in project.dependencies 521 for ( Dependency projectDependency : (List<Dependency>) this.project.getDependencyManagement().getDependencies() ) 522 { 523 if ( sameDependencyWithoutVersion( dependency, projectDependency ) ) 524 { 525 return projectDependency.getVersion(); 526 } 527 } 528 529 return null; 530 } 531 532 protected boolean sameDependencyWithoutVersion( Dependency that, Dependency dependency ) 533 { 534 return StringUtils.equals( that.getGroupId(), dependency.getGroupId() ) && StringUtils.equals( 535 that.getArtifactId(), dependency.getArtifactId() ); 536 } 537 538 protected void copyDirectoryContentIntoArchive( File sourceFolder, String destinationPath, 539 ArchiveOutputStream archiveOutputStream ) 540 throws IOException 541 { 542 543 // Scan the directory 544 DirectoryScanner directoryScanner = new DirectoryScanner(); 545 directoryScanner.setBasedir( sourceFolder ); 546 directoryScanner.addDefaultExcludes(); 547 directoryScanner.scan(); 548 549 // Each File 550 for ( String includeFileName : directoryScanner.getIncludedFiles() ) 551 { 552 getLog().debug( "include configuration file : " + destinationPath + includeFileName ); 553 File inputFile = new File( sourceFolder, includeFileName ); 554 555 FileInputStream sourceFileInputStream = null; 556 try 557 { 558 sourceFileInputStream = new FileInputStream( inputFile ); 559 560 archiveOutputStream.putArchiveEntry( new JarArchiveEntry( destinationPath + includeFileName ) ); 561 IOUtils.copy( sourceFileInputStream, archiveOutputStream ); 562 archiveOutputStream.closeArchiveEntry(); 563 } 564 finally 565 { 566 IOUtils.closeQuietly( sourceFileInputStream ); 567 } 568 } 569 570 } 571 572 /** 573 * Resolves the plugin work dir as a sub directory of {@link #buildDirectory}, creating it if it does not exist. 574 * 575 * @return File representing the resolved plugin work dir 576 * @throws MojoExecutionException if the plugin work dir cannot be created 577 */ 578 protected File resolvePluginWorkDir() 579 throws MojoExecutionException 580 { 581 if ( !pluginWorkDirectory.exists() && !pluginWorkDirectory.mkdirs() ) 582 { 583 throw new MojoExecutionException( 584 "Could not create plugin work directory at " + pluginWorkDirectory.getAbsolutePath() ); 585 } 586 587 return pluginWorkDirectory; 588 589 } 590 591 protected String[] toStringArray( List list ) 592 { 593 if ( list == null || list.isEmpty() ) 594 { 595 return new String[0]; 596 } 597 List<String> res = new ArrayList<String>( list.size() ); 598 599 for ( Iterator ite = list.iterator(); ite.hasNext(); ) 600 { 601 res.add( (String) ite.next() ); 602 } 603 return res.toArray( new String[res.size()] ); 604 } 605 606 607 /** 608 * return file can be deleted 609 */ 610 protected File addContextXmlToWar( File contextXmlFile, File warFile ) 611 throws IOException, ArchiveException 612 { 613 ArchiveOutputStream os = null; 614 OutputStream warOutputStream = null; 615 File tmpWar = File.createTempFile( "tomcat", "war-exec" ); 616 tmpWar.deleteOnExit(); 617 618 try 619 { 620 warOutputStream = new FileOutputStream( tmpWar ); 621 os = new ArchiveStreamFactory().createArchiveOutputStream( ArchiveStreamFactory.JAR, warOutputStream ); 622 os.putArchiveEntry( new JarArchiveEntry( "META-INF/context.xml" ) ); 623 IOUtils.copy( new FileInputStream( contextXmlFile ), os ); 624 os.closeArchiveEntry(); 625 626 JarFile jarFile = new JarFile( warFile ); 627 extractJarToArchive( jarFile, os, null ); 628 os.flush(); 629 } 630 finally 631 { 632 IOUtils.closeQuietly( os ); 633 IOUtils.closeQuietly( warOutputStream ); 634 } 635 return tmpWar; 636 } 637 638 /** 639 * Copy the contents of a jar file to another archive 640 * 641 * @param file The input jar file 642 * @param os The output archive 643 * @throws IOException 644 */ 645 protected void extractJarToArchive( JarFile file, ArchiveOutputStream os, String[] excludes ) 646 throws IOException 647 { 648 Enumeration<? extends JarEntry> entries = file.entries(); 649 while ( entries.hasMoreElements() ) 650 { 651 JarEntry j = entries.nextElement(); 652 653 if ( excludes != null && excludes.length > 0 ) 654 { 655 for ( String exclude : excludes ) 656 { 657 if ( SelectorUtils.match( exclude, j.getName() ) ) 658 { 659 continue; 660 } 661 } 662 } 663 664 if ( StringUtils.equalsIgnoreCase( j.getName(), "META-INF/MANIFEST.MF" ) ) 665 { 666 continue; 667 } 668 os.putArchiveEntry( new JarArchiveEntry( j.getName() ) ); 669 IOUtils.copy( file.getInputStream( j ), os ); 670 os.closeArchiveEntry(); 671 } 672 if ( file != null ) 673 { 674 file.close(); 675 } 676 } 677 }