001 /*
002 * JarFileMerger.java
003 *
004 * Copyright (c) 1995-2010, The University of Sheffield. See the file
005 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006 *
007 * This file is part of GATE (see http://gate.ac.uk/), and is free
008 * software, licenced under the GNU Library General Public License,
009 * Version 2, June 1991 (in the distribution as file licence.html,
010 * and also available at http://gate.ac.uk/gate/licence.html).
011 *
012 * Oana Hamza, 09/06/00
013 *
014 * $Id: JarFiles.java 12006 2009-12-01 17:24:28Z thomas_heitz $
015 */
016
017 package gate.util;
018
019 import java.io.*;
020 import java.util.*;
021 import java.util.jar.*;
022
023 /** This class is used to merge a set of Jar/Zip Files in a Jar File
024 * It is ignored the manifest.
025 */
026 public class JarFiles {
027
028 /** Debug flag */
029 private static final boolean DEBUG = false;
030 private StringBuffer dbgString = new StringBuffer();
031 private boolean warning = false;
032 String buggyJar = null;
033
034 private final static int BUFF_SIZE = 65000;
035
036 private Set directorySet = null;
037
038 private byte buffer[] = null;
039
040 public JarFiles(){
041 directorySet = new HashSet();
042 buffer = new byte[BUFF_SIZE];
043 }
044
045 /** This method takes the content of all jar/zip files from the set
046 * jarFileNames and put them in a file with the name outputFileName.
047 * If the jar entry is manifest then this information isn't added.
048 * @param jarFileNames is a set of names of files (jar/zip)
049 * @param destinationJarName is the name of the file which contains all the
050 * classes of jarFilesNames
051 */
052 public void merge(Set jarFileNames, String destinationJarName)
053 throws GateException {
054 String sourceJarName = null;
055 JarOutputStream jarFileDestination = null;
056 JarFile jarFileSource = null;
057
058 try {
059 // create the output jar file
060 jarFileDestination =
061 new JarOutputStream(new FileOutputStream(destinationJarName));
062
063 dbgString.append("Creating " + destinationJarName + " from these JARs:\n");
064 // iterate through the Jar files set
065 Iterator jarFileNamesIterator = jarFileNames.iterator();
066
067 while (jarFileNamesIterator.hasNext()) {
068 sourceJarName = (String) jarFileNamesIterator.next();
069
070 // create the new input jar files based on the file name
071 jarFileSource = new JarFile(sourceJarName);
072
073 // Out.println("Adding " + sourceJarName + " to "
074 // + destinationJarName);
075 addJar(jarFileDestination, jarFileSource);
076 if (jarFileSource.getName().equals(buggyJar))
077 dbgString.append(sourceJarName + "...problems occured ! \n");
078 else
079 dbgString.append(sourceJarName + "...added OK ! \n");
080 jarFileSource.close();
081 }//End while
082
083 jarFileDestination.close();
084
085 } catch(IOException ioe) {
086 ioe.printStackTrace(Err.getPrintWriter());
087 //System.exit(1);
088 }
089 if (warning == true)
090 Out.prln(dbgString);
091 }// merge
092
093
094 /**
095 * This method adds all entries from sourceJar to destinationJar
096 * NOTE: that manifest information is not added, method will throw
097 * a gate Exception if a duplicate entry file is found.
098 * @param destinationJar the jar that will collect all the entries
099 * from source jar
100 * @param sourceJar doesn't need any explanation ... DOES it?
101 */
102 private void addJar(JarOutputStream destinationJar, JarFile sourceJar)
103 throws GateException {
104 try {
105
106 // get an enumeration of all entries from the sourceJar
107 Enumeration jarFileEntriesEnum = sourceJar.entries();
108
109 JarEntry currentJarEntry = null;
110 while (jarFileEntriesEnum.hasMoreElements()) {
111
112 // get a JarEntry
113 currentJarEntry = (JarEntry) jarFileEntriesEnum.nextElement();
114
115 // if current entry is manifest then it is skipped
116 if(currentJarEntry.getName().equalsIgnoreCase("META-INF/") ||
117 currentJarEntry.getName().equalsIgnoreCase("META-INF/MANIFEST.MF"))
118 continue;
119
120 // if current entry is a directory that was previously added to the
121 // destination JAR then it is skipped
122 if( currentJarEntry.isDirectory() &&
123 directorySet.contains(currentJarEntry.getName())
124 ) continue;
125
126 // otherwise the current entry is added to the final jar file
127 try {
128 // if the entry is directory then is added to the directorySet
129 // NOTE: files entries are not added to this set
130 if (currentJarEntry.isDirectory())
131 directorySet.add(currentJarEntry.getName());
132
133 // put the entry into the destination JAR
134 destinationJar.putNextEntry(new JarEntry(currentJarEntry.getName()));
135
136 // add the binary data from the entry
137 // NOTE: if the entry is a directory there will be no binary data
138 // get an input stream from the entry
139 InputStream currentEntryStream =
140 sourceJar.getInputStream(currentJarEntry);
141
142 // write data to destinationJar
143 int bytesRead = 0;
144 while((bytesRead = currentEntryStream.read(buffer,0,BUFF_SIZE)) != -1)
145 destinationJar.write(buffer,0,bytesRead);
146
147 // close the input stream
148 currentEntryStream.close();
149
150 // flush the destinationJar in order to be sure that
151 // everything is there
152 destinationJar.flush();
153
154 // close the new added entry and prepare to read and write
155 // another one
156 // NOTE: destinationJar.putNextEntry automaticaly closes any previous
157 // opened entry
158 destinationJar.closeEntry();
159
160 } catch (java.util.zip.ZipException ze) {
161 if(!currentJarEntry.isDirectory()){
162 warning = true;
163 buggyJar = sourceJar.getName();
164 Out.prln("WARNING: Duplicate file entry " +
165 currentJarEntry.getName() + " (this file will be discarded)..." +
166 "It happened while adding " +
167 sourceJar.getName() + " !\n");
168 dbgString.append(currentJarEntry.getName() +" file from " +
169 sourceJar.getName() + " was discarded :( !\n");
170 }// End if
171 }
172 }// while(jarFileEntriesEnum.hasMoreElements())
173 } catch (java.io.IOException e) {
174 e.printStackTrace(Err.getPrintWriter());
175 // System.exit(1);
176 }
177 }// addJar
178
179 /** args[0] is the final jar file and the other are the set of
180 * jar file names
181 * e.g. java gate.util.JarFiles libs.jar ../lib/*.jar ../lib/*.zip
182 * will create a file calls libs.jar which will contain all
183 * jar files and zip files
184 */
185
186 public static void main(String[] args) {
187 if(args.length < 2) {
188 Err.println("USAGE : JarFiles arg0 arg1 ... argN" +
189 "(must be at least 2 args)");
190 //System.exit(1);
191 } else {
192 JarFiles jarFiles = new JarFiles();
193 Set filesToMerge = new HashSet();
194 for (int i=1; i<args.length; i++) {
195 filesToMerge.add(args[i]);
196 }
197 try {
198 jarFiles.merge(filesToMerge, args[0]);
199 } catch (GateException ge) {
200 ge.printStackTrace(Err.getPrintWriter());
201 }
202 }// if
203 }// main
204
205 }// class JarFiles
|