blob: 4606689417632ea4d4b4abb66f1fdca81c044cc2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.uima.pear.generate;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
/**
* {@link IRunnableWithProgress} that creates a zip file containing a given set of resources *
*/
public class PearExportOperation implements IRunnableWithProgress {
/** An array of files that should be included in the zip file */
protected final IFile[] fExports;
/** Prefix to strip off from the provided files paths */
protected final IContainer fRoot;
/** Filename for the destination zip file */
protected final String fFilename;
/** whether zip contents should be compressed */
protected final boolean fCompress;
/**
* Constructor
*
* @param exports
* An array of files that should be included in the zip file
* @param virtualRoot
* Prefix to strip off from the provided files paths, e.g. if '/foo/bar/baz.txt' is
* included and '/foo' is the virtual root, than '/bar/baz.txt' will be created in the
* zip file
* @param filename
* Filename for the destination zip file
* @param compress
* <code>true</code> if the zip contents should be compressed, <code>false</code>
* otherwise
*/
public PearExportOperation(final IFile[] exports, final IContainer virtualRoot,
final String filename, final boolean compress) {
fExports = exports;
fRoot = virtualRoot;
fFilename = filename;
fCompress = compress;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(final IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
try {
final int SCALE = 100;
final String jobName = "Exporting " + fExports.length + " files to Pear file " + fFilename
+ "...";
monitor.beginTask(jobName, 2 * SCALE * fExports.length);
// Create output zip stream
final File pearFile = new File(fFilename);
FileOutputStream fOut;
try {
fOut = new FileOutputStream(pearFile);
} catch (final FileNotFoundException exception) {
throw new InvocationTargetException(exception);
}
final ZipOutputStream stream = new ZipOutputStream(fOut);
if (monitor.isCanceled()) {
// Nothing written, just close and cancel
stream.close();
throw new OperationCanceledException();
}
// Add each file to the zip stream
for (int i = 0; i < fExports.length; ++i) {
final IFile file = fExports[i];
// Verify file is child of root
if (!fRoot.getFullPath().isPrefixOf(file.getFullPath())) {
throw new IllegalArgumentException(fRoot + " is not a parent of " + file); //$NON-NLS-1$
}
// Read file contents
String filename = file.getFullPath().toPortableString();
final String cutPath = fRoot.getFullPath().addTrailingSeparator().toPortableString();
filename = filename.substring(cutPath.length());
monitor.subTask("Adding " + filename);
final byte[] fileContents = readContents(file, new SubProgressMonitor(monitor, SCALE));
// Add contents to zip file
final ZipEntry entry = new ZipEntry(filename);
// file.getModificationStamp() seems to use a different semantic
// for the timestamp
entry.setTime(file.getLocation().toFile().lastModified());
if (fCompress) {
entry.setMethod(ZipEntry.DEFLATED);
} else {
entry.setMethod(ZipEntry.STORED);
entry.setSize(fileContents.length);
final CRC32 checksumCalculator = new CRC32();
checksumCalculator.update(fileContents);
entry.setCrc(checksumCalculator.getValue());
}
stream.putNextEntry(entry);
stream.write(fileContents);
monitor.worked(SCALE);
if (monitor.isCanceled()) {
// Close zip file and remove it, then terminate
stream.close();
pearFile.delete();
throw new OperationCanceledException();
}
}
stream.close();
} catch (final FileNotFoundException exception) {
throw new InvocationTargetException(exception);
} catch (final IOException exception) {
throw new InvocationTargetException(exception);
} finally {
monitor.done();
}
}
/**
* @param file
* The file to read
* @param monitor
* @return A byte array with the file contents
* @throws IOException
*/
private byte[] readContents(final IFile file, IProgressMonitor monitor) throws IOException {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
final File localFile = file.getLocation().toFile();
final int bufferSize = 4096;
int count = (int) (localFile.length() / bufferSize);
try {
monitor.beginTask("Reading file " + file.getFullPath().toPortableString(), count);
final FileInputStream in = new FileInputStream(localFile);
final BufferedInputStream bIn = new BufferedInputStream(in);
int length = 0;
byte[] buffer = new byte[bufferSize];
byte[] bufferCopy = new byte[bufferSize];
while ((length = bIn.read(buffer, 0, bufferSize)) != -1) {
bufferCopy = new byte[length];
System.arraycopy(buffer, 0, bufferCopy, 0, length);
output.write(bufferCopy);
monitor.worked(1);
}
bIn.close();
} finally {
monitor.done();
output.close();
}
return output.toByteArray();
}
}