All Downloads are FREE. Search and download functionalities are using the official Maven repository.

protoj.lang.ArchiveFeature Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2009 Ashley Williams
 * 
 * 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 protoj.lang;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.launch.AntMain;
import org.aspectj.lang.SoftException;

import protoj.lang.ClassesArchive.ClassesEntry;
import protoj.util.ArgRunnable;
import protoj.util.UntarTask;

/**
 * Provides support for the creation of source, javadoc, classes jar files,
 * project tar file and a self extracting project archive. This class is an
 * aggregate of implementation objects so see the {@link SourceArchive},
 * {@link JavadocArchive}, {@link ClassesArchive} and {@link ProjectArchive}
 * classes for more information.
 * 
 * @author Ashley Williams
 * 
 */
public final class ArchiveFeature {
	/**
	 * The name of the tar gz file created with
	 * {@link #createSelfExtractingArchive(boolean, boolean, boolean)}.
	 */
	private static final String PROJECT_DIST_ARCHIVE = "project-dist";

	/**
	 * See {@link #getClassesArchive()}.
	 */
	private ClassesArchive classesArchive;

	/**
	 * See {@link #getSourceArchive()}.
	 */
	private SourceArchive sourceArchive;

	/**
	 * See {@link #getJavadocArchive()}.
	 */
	private JavadocArchive javadocArchive;

	/**
	 * See {@link #getProjectArchive()}.
	 */
	private ProjectArchive projectArchive;

	/**
	 * See {@link #getProject()}.
	 */
	private final StandardProject project;

	/**
	 * A cached reference to this frequently used instance.
	 */
	private ProjectLayout layout;

	/**
	 * The name of the self extracting archive, see
	 * {@link #initSelfExtractingArchive(String, String, String, String, String)}
	 * .
	 */
	private String extractingArchiveName;

	/**
	 * Enables creation of source, javadoc and classes jar files.
	 * 
	 * @param parent
	 */
	public ArchiveFeature(StandardProject parent) {
		this.project = parent;
		this.layout = parent.getLayout();
		this.classesArchive = new ClassesArchive(this);
		this.sourceArchive = new SourceArchive(this);
		this.javadocArchive = new JavadocArchive(this);
	}

	/**
	 * This method must be called if support for creating a compressed tar file
	 * of the project is required.
	 * 
	 * @param name
	 *            the name of the tar file without any extension
	 * @param prefix
	 *            used as the name of the root directory when the tarfile is
	 *            extracted
	 * @param userName
	 *            the user name for the tar entry, can be null
	 * @param group
	 *            the group for the tar entry, can be null
	 */
	public void initProjectArchive(String name, String prefix, String userName,
			String group) {
		this.projectArchive = new ProjectArchive(this, name, prefix, userName,
				group);
	}

	/**
	 * Convenient wrapper when just the default tar is required with no
	 * customization and applying tar name suffixes as necessary. See
	 * {@link #initProjectArchive(String, String, String, String)}.
	 * 
	 * @param name
	 * @param prefix
	 */
	public void initProjectArchive(String name, String prefix) {
		initProjectArchive(name, prefix, null, null);
	}

	/**
	 * Enables the creation of a self extracting jar file with the name
	 * specified by the extractingArchiveName argument and whose contents are a
	 * compressed tar of the whole project. The resultant archive is executable
	 * and so when executed will extract the project into the same directory.
	 * 

* This works by initializing the project archive with a call to * {@link #initProjectArchive(String, String)} and configuring a new classes * archive with a call to * {@link ClassesArchive#addEntry(String, String, String, String)} and * coordinating between the two. Therefore it is advisable not to separately * call initProjectArchive. * * * @param extractingArchiveName * the name of the archive * @param jarManifest * the name of the manifest, null to accept default * @param tarPrefix * the name of the root directory when the tar is extracted * @param tarUserName * the user name for the tar entries * @param tarGroup * the group for the tar entries */ public void initSelfExtractingArchive(String extractingArchiveName, String jarManifest, String tarPrefix, String tarUserName, String tarGroup) { this.extractingArchiveName = extractingArchiveName; // enable the creation of the project tar archive initProjectArchive(PROJECT_DIST_ARCHIVE, tarPrefix, tarUserName, tarGroup); // enable the executable jar that will perform the extraction getClassesArchive().addEntry(extractingArchiveName, jarManifest, null, "**/*"); getClassesArchive().getEntry(extractingArchiveName).initConfig( new ArgRunnable() { public void run(ClassesArchive archive) { archive.initExecutableJar(ArchiveFeature.class .getName()); } }); getClassesArchive().initIncludeArchives(extractingArchiveName, getPath(Task.class).getName(), getPath(AntMain.class).getName(), getPath(Logger.class).getName(), getPath(IOUtils.class).getName(), getPath(StandardProject.class).getName(), getPath(SoftException.class).getName()); } /** * Gets the filename of the jar that contains the specified class name. * Helper for * {@link #initSelfExtractingArchive(String, String, String, String, String)} * . * * @param name * @return */ private File getPath(Class name) { File jar = new File(name.getProtectionDomain().getCodeSource() .getLocation().toURI()); return jar; } /** * Creates a self extracting archive of the project as initialized in * {@link #initSelfExtractingArchive(String, String, String, String, String)} * . * *

    *
  1. the first party jars are updated in the lib directory for those * archives that are supposed to be on the classpath - see * {@link ClassesArchive#initClasspathLib(String)}
  2. *
  3. the project tar file is created in the classes directory - see * {@link ProjectArchive#createArchive(boolean, boolean, boolean)} for an * explanation of the tar parameters below
  4. *
  5. the self extracting jar is created from the files in the classes * directory, including importantly the project tar file just mentioned
  6. *
  7. *
  8. *
* * @param noSrc * @param noClasses * @param isGlobalRwx */ public void createSelfExtractingArchive(boolean noSrc, boolean noClasses, boolean isGlobalRwx) { File srcFile = getProjectArchive().getArchiveFile(); File destFile = new File(getLayout().getClassesDir(), srcFile.getName()); // delete any previous dest file so it can't be included in next tar destFile.delete(); // ensure first party libs have been created in lib directory classesArchive.visit(new ArgRunnable() { public void run(ClassesEntry entry) { if (entry.isClasspathLib()) { String name = entry.getArchiveEntry().getName(); classesArchive.createArchive(name); } } }); // create the project tar file with no source directory getProjectArchive().createArchive(noSrc, noClasses, isGlobalRwx); // copy the tar file to the classes directory FileUtils.copyFile(srcFile, destFile); // create a jar of the classes directory which includes tar getClassesArchive().createArchive(extractingArchiveName); } /** * Deletes the target/ and classes/ directories as well as any jars that * have been copied to the lib/ directory. These are identified by finding * those classes archive entries that were configured with a call to * {@link ClassesArchive#initClasspathLib(String)}. */ public void clean() { FileUtils.deleteDirectory(getLayout().getTargetDir()); FileUtils.deleteDirectory(getLayout().getClassesDir()); getClassesArchive().visit(new ArgRunnable() { public void run(ClassesEntry entry) { if (entry.isClasspathLib()) { String name = entry.getArchiveEntry().getName(); File file = new File(getLayout().getLibDir(), name); FileUtils.deleteDirectory(file); } } }); } /** * Convenience method that schedules the creation of a single jar file with * the given name. See * {@link ClassesArchive#addEntry(String, String, String, String)} . * * @param name */ public void addClasses(String name) { getClassesArchive().addEntry(name, null, null, null); } /** * Convenience method that schedules the creation of a single javadoc * archive file with the given name and memory. See * {@link JavadocArchive#addEntry(String, String, String, String, String)} . * * @param name */ public void addJavadoc(String name, String memory) { getJavadocArchive().addEntry(name, null, null, null, memory); } /** * Convenience method that schedules the creation of a single sources * archive file with the given name and memory. See * {@link JavadocArchive#addEntry(String, String, String, String, String)} . * . * * @param name */ public void addSources(String name) { getSourceArchive().addEntry(name, null, null, null); } /** * Returns whether or not the given jar name represents a valid classes jar * file. This is a jar file that doesn't contain the strings * {@link ProjectLayout#getSourcePostfix()}, * {@link ProjectLayout#getJavadocPostfix()} or * {@link ProjectLayout#getSrcPostfix()}. * * @param name * @return */ public boolean isClassesJar(String name) { return name.endsWith(".jar") && !isSourcesJar(name) && !isJavadocJar(name); } /** * Returns whether or not the given jar name represents a valid javadoc jar * file. This is a jar file that contain the string * {@link ProjectLayout#getJavadocPostfix()}. * * @param name * @return */ public boolean isJavadocJar(String name) { return name.endsWith(".jar") && name.contains(layout.getJavadocPostfix()); } /** * Returns whether or not the given jar name represents a valid sources jar * file. This is a jar file that contains either of the strings * {@link ProjectLayout#getSourcePostfix()} or * {@link ProjectLayout#getSrcPostfix()}. * * @param name * @return */ public boolean isSourcesJar(String name) { return name.endsWith(".jar") && (name.contains(layout.getSourcePostfix()) || name .contains(layout.getSrcPostfix())); } /** * Use this instance to configure the creation of java archives from the * classes directory. See {@link ClassesArchive}. * * @return */ public ClassesArchive getClassesArchive() { return classesArchive; } /** * Use this instance to configure the creation of java archives from the * source directory. See {@link SourceArchive}. * * @return */ public SourceArchive getSourceArchive() { return sourceArchive; } /** * Use this instance to configure the creation of java archives from the * javadoc directory. See {@link JavadocArchive}. * * @return */ public JavadocArchive getJavadocArchive() { return javadocArchive; } /** * Use this instance to configure the creation of a compressed tar file for * the entire application. See {@link ProjectArchive}. * * @return */ public ProjectArchive getProjectArchive() { return projectArchive; } /** * The parent project for this feature. * * @return */ public StandardProject getProject() { return project; } /** * The parent layout for convenient access. * * @return */ public ProjectLayout getLayout() { return layout; } /** * Extracts the project contained in this executable jar. This use-case is * therefore only available when called from the executable jar created in * the first place with a call to * {@link ArchiveFeature#createSelfExtractingArchive(boolean, boolean, boolean)} * . */ public static void main(String[] args) { File container = new File(ArchiveFeature.class.getProtectionDomain() .getCodeSource().getLocation().toURI()); if (container == null) { throw new RuntimeException( "this use-case isn't being invoked from the executable jar"); } JarFile jarFile = new JarFile(container); String artifactName = PROJECT_DIST_ARCHIVE + ".tar.gz"; File artifactFile = new File(".", artifactName); ZipEntry artifactEntry = jarFile.getEntry(artifactName); InputStream source = jarFile.getInputStream(artifactEntry); try { FileOutputStream dest = new FileOutputStream(artifactFile); try { IOUtils.copy(source, dest); } finally { IOUtils.closeQuietly(dest); } } finally { IOUtils.closeQuietly(source); } UntarTask untarTask = new UntarTask(artifactFile, new File(".")); untarTask.initCompression("gzip"); untarTask.execute(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy