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

protoj.lang.ClassesArchive 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.FilenameFilter;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.io.FileUtils;

import protoj.util.ArgRunnable;
import protoj.util.AssembleTask;

/**
 * Responsible for creating one or more archives from the project classes
 * directory. Call {@link #addEntry(String, String, String, String)} to
 * configure each additional archive with the specified name and
 * {@link #createArchive(String)} to create one of the added archive. During
 * creation, the config argument specified in the constructor will
 * be called back to give the caller a chance to provide further archive
 * configuration. Also call {@link #initIncludeArchives(String, String...)} to
 * cause any additional archives from the {@link ProjectLayout#getLibDir()} to
 * be merged with the added archive.
 * 
 * @author Ashley Williams
 * 
 */
public final class ClassesArchive {
	/**
	 * Adds classes specific information to a wrapped {@link ArchiveEntry}
	 * instance.
	 * 
	 * @author Ashley Williams
	 * 
	 */
	public static final class ClassesEntry {
		/**
		 * See {@link #getArchiveEntry()}.
		 */
		private ArchiveEntry archiveEntry;

		/**
		 * See {@link #getPomResource()}.
		 */
		private String pomResource;

		/**
		 * See {@link #getGpgOptions()}.
		 */
		private String gpgOptions;

		private boolean isClasspathLib;

		/**
		 * See the {@link ArchiveEntry} accessors.
		 * 
		 * @param parent
		 * @param name
		 *            TODO
		 * @param fileName
		 * @param manifest
		 * @param includes
		 * @param excludes
		 */
		public ClassesEntry(ArchiveFeature parent, String name,
				String fileName, String manifest, String includes,
				String excludes) {
			this.archiveEntry = new ArchiveEntry(name, parent,
					fileName, manifest, includes, excludes);
			this.isClasspathLib = false;
		}

		/**
		 * Pass-thru method to {@link ArchiveEntry#initConfig(ArgRunnable)}.
		 * 
		 * @param config
		 */
		public void initConfig(ArgRunnable config) {
			archiveEntry.initConfig(config);
		}

		/**
		 * Call this method if the archive should be copied to the lib/
		 * directory after creation. If this isn't called then this archive
		 * won't be copied.
		 */
		public void initClasspathLib() {
			this.isClasspathLib = true;
		}

		/**
		 * Specifies the information used in publishing the artifact. Javadoc
		 * and source archives of the same name will automatically get attached
		 * and published so there is no equivalent method on those.
		 * 

* The pomResource is used to specify the location on the classpath of * the maven pom file describing the artifact to be published, for * example "/proj/pom-pub.xml". Veolcity markup for interacting with the * domain objects can be specified in in order to avoid hardcoded * values. *

* If the gpg executable is available to the operating system then * options can be specified to produce the ascii armored detached * signature file to also be published. Simply specify a string that * will be passed to String.format() whose first parameter is the name * of the file to be signed and the second parameter is the name of the * signature file to be created. Here is an example: * *

		 * "--armor --output %2$s --detach-sign %1$s"
		 * 
* * The publish feature will correctly pass in the two arguments for each * archive. Hint: to supply additional options such as --local-user, * read in a system property when composing the string. * * @param pomResource * the name of the classpath pom resource used to publish the * artifact. * @param gpgOptions * the options to the gpg executable that will generate the * ascii armored detached signature file, or null if signing * isn't required. */ public void initPublish(String pomResource, String gpgOptions) { this.pomResource = pomResource; this.gpgOptions = gpgOptions; } /** * The maven pom resource on the classpath used to publish the artifact * in this entry. See {@link #initPublish(String, String)} for more * information. * * @return */ public String getPomResource() { return pomResource; } /** * The options to gpg responsible for creating the ascii armored * detached signature file. See {@link #initPublish(String, String)} for * more information. * * @return */ public String getGpgOptions() { return gpgOptions; } /** * The wrapped helper. * * @return */ public ArchiveEntry getArchiveEntry() { return archiveEntry; } /** * True if the generated jar is to be copied to the lib/ directory, * false otherwise. * * @return */ public boolean isClasspathLib() { return isClasspathLib; } } /** * The parent that owns this instance lifecycle. */ private final ArchiveFeature parent; /** * The configuration information for each added archive. */ private TreeMap entries = new TreeMap(); /** * See {@link #getCurrentAssembleTask()}. */ private AssembleTask currentAssembleTask; /** * See {@link #getCurrentEntry()}. */ private ArchiveEntry currentEntry; /** * Creates with the parent feature. * * @param parent */ public ClassesArchive(ArchiveFeature parent) { this.parent = parent; } /** * Use to enable creation of an additional archive. * * @param name * the name of the jar file to be created, without the extension. * @param manifest * the name of the manifest to be used from the manifest * directory, without the extension. Can be null if a default * manifest is required. * @param includes * the resources that should be included in the archive, can be * null to include all resources * @param excludes * the resources that should be excluded in the archive, can be * null to exclude no resources */ public void addEntry(String name, String manifest, String includes, String excludes) { String fileName = name + ".jar"; ClassesEntry entry = new ClassesEntry(parent, name, fileName, manifest, includes, excludes); entries.put(name, entry); } /** * Pass-thru method to {@link ArchiveEntry#initConfig(ArgRunnable)}. * * @param config */ public void initConfig(String name, ArgRunnable config) { getEntry(name).initConfig(config); } /** * Call this method if publishing to a maven repository is required. * Pass-thru method to {@link ClassesEntry#initPublish(String, String)}. * * @param name * @param pomName * @param gpgOptions */ public void initPublish(String name, String pomName, String gpgOptions) { getEntry(name).initPublish(pomName, gpgOptions); } /** * Call this method if the archive should be copied to the lib/ directory * after creation. Pass-thru method to * {@link ClassesEntry#initClasspathLib()}. * * @param name */ public void initClasspathLib(String name) { getEntry(name).initClasspathLib(); } /** * Pass-thru method that ensures the specified archives are merged to the * named archive. See {@link ArchiveEntry#initMergeArchives(String...)}. * * @param name * @param archives */ public void initIncludeArchives(String name, String... archives) { getEntry(name).getArchiveEntry().initMergeArchives(archives); } /** * Specifies that all the classes archives except for the excluded list in * the {@link ProjectLayout#getLibDir()} should get merged during creation * of the named archive. * * @param name */ public void initExcludeArchives(String name, String... archives) { final List excluded = Arrays.asList(archives); FilenameFilter filter = new FilenameFilter() { public boolean accept(File dir, String name) { //reject if excluded or javadoc/sources jar return !excluded.contains(name) && parent.isClassesJar(name); } }; getEntry(name).getArchiveEntry().initMergeArchives(filter); } /** * Delegates to {@link #createArchive(String)} for each archive that was * added through a call to {@link #addEntry(String, String, String, String)} * . */ public void createArchives() { Set keys = entries.keySet(); for (String key : keys) { createArchive(key); } } /** * Creates the jar for the given name under * {@link ProjectLayout#getArchiveDir()}. The jar file will have a name of * [name].jar. Additionally copies the jar to the lib directory if it is a * classpath lib, i.e. initClasspathLib() has been called. * * @param name * the name as specified in the call to * {@link #addEntry(String, String, String, String)} . */ public void createArchive(String name) { ProjectLayout layout = parent.getProject().getLayout(); currentEntry = getEntry(name).getArchiveEntry(); currentAssembleTask = currentEntry.createAssembleTask(layout .getClassesDir()); ArgRunnable config = currentEntry.getConfig(); if (config != null) { config.run(this); } currentAssembleTask.execute(); boolean isClasspathLib = getEntry(name).isClasspathLib(); if (isClasspathLib) { FileUtils.copyFileToDirectory(currentEntry.getArtifact(), layout .getLibDir()); } } /** * Accessor for the entry corresponding to the given name. * * @param name * @return */ public ClassesEntry getEntry(String name) { return entries.get(name); } /** * Convenience method that delegates to {@link #initExecutableJar(String)}, * but using the current thread main class by default. */ public void initExecutableJar() { String currentMainClass = parent.getProject().getDispatchFeature() .getCurrentMainClass(); initExecutableJar(currentMainClass); } /** * Marks the archive as an executable jar with the specified mainClass. * Works in conjunction with the * {@link #initIncludeArchives(String, String...)} method, since any archive * that is to be merged won't appear in the Class-Path attribute value. *

* This should be invoked on the callback to the config parameter specified * in the call to {@link #addEntry(String, String, String, String)}. Ensures * the given ant assemble task is configured to create an executable jar. * The jar files in the lib directory are used to form the Class-Path string * in the manifest file. * * @param mainClass */ public void initExecutableJar(String mainClass) { StringBuilder classPath = new StringBuilder(); String[] libFiles = parent.getLayout().getLibDir().list(); List mergeArchives = getCurrentEntry().getMergeArchives(); for (String libFile : libFiles) { boolean isClassesJar = parent.isClassesJar(libFile); boolean isMergeArchive = mergeArchives.contains(libFile); if (isClassesJar && !isMergeArchive) { classPath.append(libFile); classPath.append(" "); } } getCurrentAssembleTask().initManifest("Main-Class", mainClass); getCurrentAssembleTask().initManifest("Class-Path", classPath.toString()); } /** * Convenient method that visits each entry in this archive. * * @param visitor */ public void visit(ArgRunnable visitor) { Collection values = entries.values(); for (ClassesEntry entry : values) { visitor.run(entry); } } /** * The ant task responsible for creating the jar during the call to * {@link #createArchive(String)}. * * @return */ public AssembleTask getCurrentAssembleTask() { return currentAssembleTask; } /** * The instance used to hold information about the the archive being created * during the call to {@link #createArchive(String)}. * * @return */ public ArchiveEntry getCurrentEntry() { return currentEntry; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy