/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* CarUnsourcer.java
* Creation date: Nov 15, 2006.
* By: Edward Lam
*/
package org.openquark.cal.services;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.logging.Logger;
import org.openquark.util.IOStreams;
/**
* Helper class to create a car or car jar by stripping an existing such archive of its cal source.
*
* This class is not meant to be instantiated or subclassed.
*
* @author Edward Lam
*/
final class CarUnsourcer {
/** The base folder for cal source. */
private static final String baseCalSourceFolderPathString = CALSourcePathMapper.SCRIPTS_BASE_FOLDER;
/** The file extension for cal source. */
private static final String calSourceFileExtension = CALSourcePathMapper.CAL_FILE_EXTENSION;
/**
* Take the specified car or car jar and generate a new one without source in the specified output location.
*
* @param carOrCarJarPath the path to the car or car jar.
* @param outputFolderString the output folder.
* @param logger the logger to which messages will be logged.
*/
public static void unsourceCar(String carOrCarJarPath, String outputFolderString, Logger logger) throws FileNotFoundException, IOException {
logger.info("Creating unsourced archive from: \"" + carOrCarJarPath + "\"");
JarFile jarFile = new JarFile(carOrCarJarPath);
try {
if (jarFile.getEntry(CarBuilder.CAR_MARKER_NAME) == null) {
throw new IOException("Not a car: " + carOrCarJarPath);
}
String baseName = (new File(carOrCarJarPath)).getName();
File outputFile = new File(outputFolderString, baseName);
FileOutputStream fos = new FileOutputStream(outputFile);
boolean outfileOk = false;
try {
BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);
JarOutputStream jos = new JarOutputStream(bos);
try {
for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); ) {
JarEntry injarEntry = entries.nextElement();
JarEntry outjarEntry = createOutjarEntry(injarEntry);
jos.putNextEntry(outjarEntry);
String injarEntryName = injarEntry.getName();
ResourcePath.FilePath filePathFromJarEntry = getFilePathFromJarEntry(injarEntryName);
String entryPathString = filePathFromJarEntry.getPathString();
if (entryPathString.startsWith(baseCalSourceFolderPathString) && entryPathString.endsWith(calSourceFileExtension)) {
// It's the source file.
// Don't transfer the data.
} else {
try {
IOStreams.transferData(jarFile.getInputStream(injarEntry), jos);
} finally {
jos.closeEntry();
}
}
}
outfileOk = true;
} finally {
jos.flush();
bos.flush();
jos.close();
bos.close();
}
} catch (IOException e) {
outfileOk = false;
throw e;
} finally {
fos.close();
// delete the incomplete Car if the operation failed with an exception
if (!outfileOk) {
outputFile.delete();
} else {
logger.info("Wrote output file: " + outputFile);
}
}
} finally {
jarFile.close();
}
}
/**
* Create a new jar entry from an existing entry.
* This entry will be suitable for use in a new jar file.
*
* This is different from the constructor JarEntry(otherJarEntry), which will copy all fields.
* Copying all fields is undesirable, since we want the new jar entry to not have some fields (such as size) set.
* These fields cannot be unset once set -- for instance, calling jarEntry.setSize(-1) will cause a RuntimeException.
*
* @param injarEntry the existing entry.
* @return a new jar entry, based on the existing entry, suitable for use in a new jar file.
*/
private static final JarEntry createOutjarEntry(JarEntry injarEntry) {
// Just copy the name, the comment, and any extra data.
JarEntry outjarEntry = new JarEntry(injarEntry.getName());
outjarEntry.setComment(injarEntry.getComment());
outjarEntry.setExtra(injarEntry.getExtra());
return outjarEntry;
}
/**
* Convert a jar entry name to a file path.
* @param entryName the entry name.
* @return a file path corresponding to the entry name.
* Slashes in the entry name will be treated as delimiters separating segments of the entry.
*/
private static final ResourcePath.FilePath getFilePathFromJarEntry(String entryName) {
String[] strings = entryName.split("\\/");
ResourcePath.Folder folder = ResourcePath.EMPTY_PATH;
for (int i = 0; i < strings.length - 1; i++) {
folder = folder.extendFolder(strings[i]);
}
return folder.extendFile(strings[strings.length - 1]);
}
}