Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2012-2015 the original author or authors.
*
* Licensed 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 io.joshworks.snappy.maven.tools;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* Utility class that can be used to repackage an archive so that it can be executed using
* '{@literal java -jar}'.
*
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class Repackager {
private static final String MAIN_CLASS_ATTRIBUTE = "Main-Class";
private static final String START_CLASS_ATTRIBUTE = "Start-Class";
private static final String BOOT_VERSION_ATTRIBUTE = "Snappy-Version";
private static final byte[] ZIP_FILE_HEADER = new byte[]{'P', 'K', 3, 4};
private final File source;
private String mainClass;
private boolean backupSource = true;
private Layout layout;
public Repackager(File source) {
if (source == null || !source.exists() || !source.isFile()) {
throw new IllegalArgumentException("Source must refer to an existing file");
}
this.source = source.getAbsoluteFile();
this.layout = Layouts.forFile(source);
}
/**
* Sets the main class that should be run. If not specified the value from the
* MANIFEST will be used, or if no manifest entry is found the archive will be
* searched for a suitable class.
*
* @param mainClass the main class name
*/
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
}
/**
* Sets if source files should be backed up when they would be overwritten.
*
* @param backupSource if source files should be backed up
*/
public void setBackupSource(boolean backupSource) {
this.backupSource = backupSource;
}
/**
* Sets the layout to use for the jar. Defaults to {@link Layouts#forFile(File)}.
*
* @param layout the layout
*/
public void setLayout(Layout layout) {
if (layout == null) {
throw new IllegalArgumentException("Layout must not be null");
}
this.layout = layout;
}
/**
* Repackage the source file so that it can be run using '{@literal java -jar}'.
*
* @param libraries the libraries required to run the archive
* @throws IOException if the file cannot be repackaged
*/
public void repackage(Libraries libraries) throws IOException {
repackage(this.source, libraries);
}
/**
* Repackage to the given destination so that it can be launched using '
* {@literal java -jar}'.
*
* @param destination the destination file (may be the same as the source)
* @param libraries the libraries required to run the archive
* @throws IOException if the file cannot be repackaged
*/
public void repackage(File destination, Libraries libraries) throws IOException {
repackage(destination, libraries, null);
}
/**
* Repackage to the given destination so that it can be launched using '
* {@literal java -jar}'.
*
* @param destination the destination file (may be the same as the source)
* @param libraries the libraries required to run the archive
* @param launchScript an optional launch script prepended to the front of the jar
* @throws IOException if the file cannot be repackaged
* @since 1.3.0
*/
public void repackage(File destination, Libraries libraries,
LaunchScript launchScript) throws IOException {
if (destination == null || destination.isDirectory()) {
throw new IllegalArgumentException("Invalid destination");
}
if (libraries == null) {
throw new IllegalArgumentException("Libraries must not be null");
}
if (alreadyRepackaged()) {
return;
}
destination = destination.getAbsoluteFile();
File workingSource = this.source;
if (this.source.equals(destination)) {
workingSource = new File(this.source.getParentFile(),
this.source.getName() + ".original");
workingSource.delete();
renameFile(this.source, workingSource);
}
destination.delete();
try {
JarFile jarFileSource = new JarFile(workingSource);
try {
repackage(jarFileSource, destination, libraries, launchScript);
} finally {
jarFileSource.close();
}
} finally {
if (!this.backupSource && !this.source.equals(workingSource)) {
deleteFile(workingSource);
}
}
}
private boolean alreadyRepackaged() throws IOException {
JarFile jarFile = new JarFile(this.source);
try {
Manifest manifest = jarFile.getManifest();
return (manifest != null && manifest.getMainAttributes()
.getValue(BOOT_VERSION_ATTRIBUTE) != null);
} finally {
jarFile.close();
}
}
private void repackage(JarFile sourceJar, File destination, Libraries libraries,
LaunchScript launchScript) throws IOException {
JarWriter writer = new JarWriter(destination, launchScript);
try {
final List unpackLibraries = new ArrayList();
final List standardLibraries = new ArrayList();
libraries.doWithLibraries(new LibraryCallback() {
@Override
public void library(Library library) throws IOException {
File file = library.getFile();
if (isZip(file)) {
if (library.isUnpackRequired()) {
unpackLibraries.add(library);
} else {
standardLibraries.add(library);
}
}
}
});
writer.writeManifest(buildManifest(sourceJar));
Set seen = new HashSet();
writeNestedLibraries(unpackLibraries, seen, writer);
writer.writeEntries(sourceJar);
writeNestedLibraries(standardLibraries, seen, writer);
if (this.layout.isExecutable()) {
writer.writeLoaderClasses();
}
} finally {
try {
writer.close();
} catch (Exception ex) {
// Ignore
}
}
}
private void writeNestedLibraries(List libraries, Set alreadySeen,
JarWriter writer) throws IOException {
for (Library library : libraries) {
String destination = Repackager.this.layout
.getLibraryDestination(library.getName(), library.getScope());
if (destination != null) {
if (!alreadySeen.add(destination + library.getName())) {
throw new IllegalStateException(
"Duplicate library " + library.getName());
}
writer.writeNestedLibrary(destination, library);
}
}
}
private boolean isZip(File file) {
try {
FileInputStream fileInputStream = new FileInputStream(file);
try {
return isZip(fileInputStream);
} finally {
fileInputStream.close();
}
} catch (IOException ex) {
return false;
}
}
private boolean isZip(InputStream inputStream) throws IOException {
for (int i = 0; i < ZIP_FILE_HEADER.length; i++) {
if (inputStream.read() != ZIP_FILE_HEADER[i]) {
return false;
}
}
return true;
}
private Manifest buildManifest(JarFile source) throws IOException {
Manifest manifest = source.getManifest();
if (manifest == null) {
manifest = new Manifest();
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
}
manifest = new Manifest(manifest);
String startClass = this.mainClass;
if (startClass == null) {
startClass = manifest.getMainAttributes().getValue(MAIN_CLASS_ATTRIBUTE);
}
if (startClass == null) {
startClass = findMainMethod(source);
}
String launcherClassName = this.layout.getLauncherClassName();
if (launcherClassName != null) {
manifest.getMainAttributes().putValue(MAIN_CLASS_ATTRIBUTE,
launcherClassName);
if (startClass == null) {
throw new IllegalStateException("Unable to find main class");
}
manifest.getMainAttributes().putValue(START_CLASS_ATTRIBUTE, startClass);
} else if (startClass != null) {
manifest.getMainAttributes().putValue(MAIN_CLASS_ATTRIBUTE, startClass);
}
String snappyVersion = getClass().getPackage().getImplementationVersion();
manifest.getMainAttributes().putValue(BOOT_VERSION_ATTRIBUTE, snappyVersion);
return manifest;
}
protected String findMainMethod(JarFile source) throws IOException {
return MainClassFinder.findSingleMainClass(source,
this.layout.getClassesLocation());
}
private void renameFile(File file, File dest) {
if (!file.renameTo(dest)) {
throw new IllegalStateException(
"Unable to rename '" + file + "' to '" + dest + "'");
}
}
private void deleteFile(File file) {
if (!file.delete()) {
throw new IllegalStateException("Unable to delete '" + file + "'");
}
}
}