001: /*
002: * MCS Media Computer Software Copyright (c) 2005 by MCS
003: * -------------------------------------- Created on 16.01.2004 by w.klaas
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
006: * use this file except in compliance with the License. You may obtain a copy of
007: * the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014: * License for the specific language governing permissions and limitations under
015: * the License.
016: */
017: package de.mcs.utils;
018:
019: import java.io.BufferedInputStream;
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileNotFoundException;
023: import java.io.FileOutputStream;
024: import java.io.FilePermission;
025: import java.io.IOException;
026: import java.security.AccessControlException;
027: import java.util.Hashtable;
028: import java.util.Iterator;
029: import java.util.Map;
030: import java.util.jar.JarOutputStream;
031: import java.util.zip.ZipEntry;
032: import java.util.zip.ZipInputStream;
033: import java.util.zip.ZipOutputStream;
034:
035: /**
036: * Modifies files in an .ear or .jar archive file.
037: *
038: * @author j.froehlich
039: */
040: public class XarUpdater {
041:
042: /** the archive file to work with. */
043: private File archiveFile;
044:
045: /** the archive file to work with. */
046: private ZipInputStream archive;
047:
048: /** the base directory. */
049: private String baseDirPath; // OS dependent path
050:
051: /** temp name of a file. */
052: private String zipname;
053:
054: /**
055: * converting a filename to a zip name.
056: *
057: * @param osFilename
058: * filename to convert
059: * @return converted name.
060: */
061: private String toZipName(final String osFilename) {
062: String zipName = osFilename;
063: if (null != baseDirPath && baseDirPath.length() > 0
064: && baseDirPath.length() < osFilename.length()
065: && osFilename.startsWith(baseDirPath)) {
066:
067: zipName = osFilename.substring(baseDirPath.length() + 1);
068: }
069: return zipName.replace(File.separatorChar, '/');
070: }
071:
072: /**
073: * Constructing the xar updater.
074: *
075: * @param aArchiveFile
076: * The archive file to use.
077: * @param baseDirFile
078: * the base file to work with.
079: * @throws IOException
080: * if something goes wrong.
081: */
082: public XarUpdater(final File aArchiveFile, final File baseDirFile)
083: throws IOException {
084: super ();
085: if (!aArchiveFile.exists()) {
086: throw new FileNotFoundException(aArchiveFile
087: .getAbsolutePath());
088: }
089: if (!aArchiveFile.canWrite()) {
090: throw new AccessControlException("No write access",
091: new FilePermission(aArchiveFile.getAbsolutePath(),
092: "write"));
093: }
094: this .archiveFile = aArchiveFile;
095:
096: // File(".");
097: if (null == baseDirFile) {
098: throw new NullPointerException(
099: "baseDirFile should not be null.");
100: }
101: if (!baseDirFile.exists()) {
102: throw new FileNotFoundException(baseDirFile
103: .getCanonicalPath());
104: }
105: if (0 == baseDirFile.getName().length()) {
106: baseDirPath = new File(System.getProperty("java.io.tmpdir"))
107: .getPath(); // new
108: } else {
109: baseDirPath = baseDirFile.getPath();
110: }
111:
112: zipname = toZipName(aArchiveFile.getPath());
113: }
114:
115: /**
116: * Constructing the xar updater.
117: *
118: * @param archiveFilename
119: * The archive file to use.
120: * @param baseDir
121: * the base file to work with.
122: * @throws IOException
123: * if something goes wrong.
124: */
125: public XarUpdater(final String archiveFilename, final String baseDir)
126: throws IOException {
127: this (new File(archiveFilename), new File(baseDir));
128: }
129:
130: /**
131: * @return getting the archive file.
132: */
133: public final File getFile() {
134: return archiveFile;
135: }
136:
137: /** some special dir and file names. */
138: static final String METAINF_NAME = "META-INF/";
139:
140: /** some special dir and file names. */
141: static final String INDEX_NAME = METAINF_NAME + "INDEX.LIST";
142:
143: /** some special dir and file names. */
144: static final String MANIFEST_NAME = METAINF_NAME + "MANIFEST.MF";
145:
146: /**
147: * adding a file to the zip.
148: *
149: * @param zipoutputstream
150: * the outputstream
151: * @param aName
152: * name of the entry
153: * @param file
154: * the file to add
155: * @param buffer
156: * a buffer
157: * @throws IOException
158: * if something goes wrong.
159: */
160: public final void addFile(final ZipOutputStream zipoutputstream,
161: final String aName, final File file, final byte[] buffer)
162: throws IOException {
163: String name = aName;
164: boolean isDir = file.isDirectory();
165: if (isDir) {
166: name = name.endsWith("/") ? name : name + "/";
167: }
168: if (name.startsWith("/")) {
169: name = name.substring(1);
170: } else if (name.startsWith("./")) {
171: name = name.substring(2);
172: }
173:
174: if (name.equals("") || name.equals(".") || name.equals(zipname)) {
175: return;
176: }
177:
178: long l = isDir ? 0L : file.length();
179:
180: // System.out.print("is file:" + name);
181: // System.out.println(" length:" + Long.toString(l));
182:
183: ZipEntry zipentry = new ZipEntry(name);
184: zipentry.setTime(file.lastModified());
185: zipentry.setMethod(ZipEntry.DEFLATED);
186: if (l == 0L) {
187: zipentry.setMethod(0);
188: zipentry.setSize(0L);
189: zipentry.setCrc(0L);
190: }
191: zipoutputstream.putNextEntry(zipentry);
192: if (!isDir) {
193: BufferedInputStream bufferedinputstream = new BufferedInputStream(
194: new FileInputStream(file));
195: int i;
196: while ((i = bufferedinputstream.read(buffer, 0,
197: buffer.length)) > 0) {
198: zipoutputstream.write(buffer, 0, i);
199: }
200:
201: bufferedinputstream.close();
202: }
203: zipoutputstream.closeEntry();
204:
205: }
206:
207: /**
208: * update an archive.
209: *
210: * @param toArchiveFile
211: * the archive file to update
212: * @param files
213: * the files to zip
214: * @param asNames
215: * as which names
216: * @throws IOException
217: * if something goes wrong.
218: */
219: public final void update(final File toArchiveFile,
220: final File[] files, final String[] asNames)
221: throws IOException {
222:
223: if (null == archive) {
224: archive = new ZipInputStream(new FileInputStream(
225: archiveFile));
226: }
227:
228: if (null == files) {
229: return;
230: }
231: Hashtable<String, File> hashtable = new Hashtable<String, File>();
232: for (int index = 0; index < files.length; index++) {
233: String name = toZipName(files[index].getPath());
234: if (null != asNames && null != asNames[index]) {
235: name = asNames[index];
236: }
237: hashtable.put(name, files[index]);
238: }
239: hashtable.remove(INDEX_NAME); // currently no META-INF/INDEX.LIST
240: // support at all
241: hashtable.remove(MANIFEST_NAME); // currently no META-INF/MANIFEST.MF
242: // update support
243:
244: JarOutputStream jaroutputstream = new JarOutputStream(
245: new FileOutputStream(toArchiveFile));
246: jaroutputstream
247: .setLevel(java.util.zip.Deflater.BEST_COMPRESSION);
248:
249: byte[] buffer = new byte[8 * 1024];
250: ZipEntry zipentry;
251: while (null != (zipentry = archive.getNextEntry())) {
252: String name = zipentry.getName();
253: if (!name.equalsIgnoreCase(INDEX_NAME)) {
254: if (!hashtable.containsKey(name)) {
255: ZipEntry newEntry = new ZipEntry(name);
256: newEntry.setMethod(zipentry.getMethod());
257: newEntry.setTime(zipentry.getTime());
258: newEntry.setComment(zipentry.getComment());
259: newEntry.setExtra(zipentry.getExtra());
260: if (ZipEntry.STORED == zipentry.getMethod()) {
261: newEntry.setSize(zipentry.getSize());
262: newEntry.setCrc(zipentry.getCrc());
263: }
264: jaroutputstream.putNextEntry(newEntry);
265: int len;
266: while ((len = archive
267: .read(buffer, 0, buffer.length)) != -1) {
268: jaroutputstream.write(buffer, 0, len);
269: }
270: } else {
271: addFile(jaroutputstream, name, (File) hashtable
272: .get(name), buffer);
273: hashtable.remove(name);
274: }
275: }
276: }
277:
278: if (!hashtable.isEmpty()) {
279: for (Iterator iter = hashtable.entrySet().iterator(); iter
280: .hasNext();) {
281: Map.Entry entry = (Map.Entry) iter.next();
282: addFile(jaroutputstream, (String) entry.getKey(),
283: (File) entry.getValue(), buffer);
284: }
285: }
286:
287: jaroutputstream.close();
288:
289: }
290:
291: /**
292: * closing the zip file.
293: *
294: * @throws IOException
295: * if something goes wrong.
296: */
297:
298: public final void close() throws IOException {
299: if (null != archive) {
300: archive.close();
301: archive = null;
302: }
303: }
304:
305: /**
306: * @return string representing this object.
307: * @see java.lang.Object#toString()
308: */
309: public final String toString() {
310: return archiveFile.toString();
311: }
312:
313: }
|