package org.codehaus.mojo.runtime.util; /* * Copyright (c) 2004, Codehaus.org * * 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.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.StringUtils; /** * adapted from the JarMojo from maven-jar-plugin * * @author jesse * @version $Id$ */ public class JarMaker { private File jarFile; private byte[] buffer = new byte[4096]; private Map includes = new HashMap(); private Map manifestEntries = new HashMap(); public JarMaker( String fullFileName ) { jarFile = new File( fullFileName ); } public JarMaker( File directory, String name ) { jarFile = new File( directory, name ); } public void addManifestEntries( Map entries ) { manifestEntries.putAll( entries ); } public void addManifestEntry( String key, String value ) { manifestEntries.put( key, value ); } /** * Add all files in the specified directory to the archive. * * @param baseDir the directory to add */ protected void addDirectory( File baseDir ) throws IOException { addDirectory( "", baseDir ); } /** * Add all files in the specified directory to the archive. * * @param prefix value to be added to the front of jar entry names * @param baseDir the directory to add */ public void addDirectory( String prefix, File baseDir ) throws IOException { addDirectory( null, null, prefix, baseDir ); } /** * Add all files in the specified directory to the archive. * * @param includesPattern Sets the list of include patterns to use * @param excludesPattern Sets the list of exclude patterns to use * @param prefix value to be added to the front of jar entry names * @param baseDir the directory to add */ public void addDirectory( String includesPattern, String excludesPattern, String prefix, File baseDir ) throws IOException { if ( !baseDir.exists() ) { return; } DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir( baseDir ); if ( includesPattern != null ) { scanner.setIncludes( StringUtils.split( includesPattern, "," ) ); } if ( excludesPattern != null ) { scanner.setExcludes( StringUtils.split( excludesPattern, "," ) ); } scanner.scan(); String[] files = scanner.getIncludedFiles(); for ( int i = 0; i < files.length; i++ ) { String file = files[i]; file = file.replace( '\\', '/' ); // todo shouldn't the scanner return platform independent names? includes.put( prefix + file, new File( baseDir, file ) ); } } /** * Create the jar file specified and include the listed files. * * @throws IOException if there is a problem writing the archive or reading the sources */ public void create() throws IOException { File parentJarFile = jarFile.getParentFile(); if ( !parentJarFile.exists() ) { parentJarFile.mkdirs(); } JarOutputStream jos = createJar( jarFile, createManifest() ); try { addEntries( jos, includes ); } finally { jos.close(); } } /** * Create the specified jar file and return a JarOutputStream to it * * @param jarFile the jar file to create * @param mf the manifest to use * @return a JarOutputStream that can be used to write to that file * @throws IOException if there was a problem opening the file */ protected JarOutputStream createJar( File jarFile, Manifest mf ) throws IOException { jarFile.getParentFile().mkdirs(); FileOutputStream fos = new FileOutputStream( jarFile ); try { return new JarOutputStream( fos, mf ); } catch ( IOException e ) { try { fos.close(); jarFile.delete(); } catch ( IOException e1 ) { // ignore } throw e; } } /** * Create a manifest for the jar file * * @return a default manifest; the Manifest-Version and Created-By attributes are initialized */ protected Manifest createManifest() { Manifest mf = new Manifest(); Attributes attrs = mf.getMainAttributes(); attrs.putValue( Attributes.Name.MANIFEST_VERSION.toString(), "1.0" ); attrs.putValue( "Created-By", "JarMaker" ); for ( Iterator i = manifestEntries.keySet().iterator(); i.hasNext(); ) { String key = (String) i.next(); attrs.putValue( key, (String) manifestEntries.get( key ) ); } return mf; } /** * Add all entries in the supplied Map to the jar * * @param jos a JarOutputStream that can be used to write to the jar * @param includes a Map<String, File> of entries to add * @throws IOException if there is a problem writing the archive or reading the sources */ protected void addEntries( JarOutputStream jos, Map includes ) throws IOException { for ( Iterator i = includes.entrySet().iterator(); i.hasNext(); ) { Map.Entry entry = (Map.Entry) i.next(); String name = (String) entry.getKey(); File file = (File) entry.getValue(); addEntry( jos, name, file ); } } /** * Add a single entry to the jar * * @param jos a JarOutputStream that can be used to write to the jar * @param name the entry name to use; must be '/' delimited * @param source the file to add * @throws IOException if there is a problem writing the archive or reading the sources */ protected void addEntry( JarOutputStream jos, String name, File source ) throws IOException { FileInputStream fis = new FileInputStream( source ); try { jos.putNextEntry( new JarEntry( name ) ); int count; while ( ( count = fis.read( buffer ) ) > 0 ) { jos.write( buffer, 0, count ); } jos.closeEntry(); } finally { fis.close(); } } }