159028 [JarProcessor] Support options controlling processing of nested jars
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/CommandStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/CommandStep.java
index 680607f..4180d28 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/CommandStep.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/CommandStep.java
@@ -11,6 +11,7 @@
 package org.eclipse.update.internal.jarprocessor;
 
 import java.io.File;
+import java.util.List;
 import java.util.Properties;
 
 /**
@@ -62,7 +63,7 @@
 		return options;
 	}
 	
-	public void adjustInf(File input, Properties inf) {
+	public void adjustInf(File input, Properties inf, List containers) {
 		//nothing
 	}
 }
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/IProcessStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/IProcessStep.java
index 20d4500..18c438e 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/IProcessStep.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/IProcessStep.java
@@ -11,6 +11,7 @@
 package org.eclipse.update.internal.jarprocessor;
 
 import java.io.File;
+import java.util.List;
 import java.util.Properties;
 
 /**
@@ -33,18 +34,20 @@
 	 *  return the file containing the result of the processing
 	 * @param input
 	 * @param workingDirectory
+	 * @param containers: inf properties for containing jars, innermost jar is first on the list
 	 * @return
 	 */
-	public File preProcess(File input, File workingDirectory);
+	public File preProcess(File input, File workingDirectory, List containers);
 	
 	/**
 	 * Perform some processing on the input file after the JarProcessor returns from recursion
 	 * return the file containing the result of the processing
 	 * @param input
 	 * @param workingDirectory
+	 * @param containers: inf properties for containing jars, innermost jar is first on the list
 	 * @return
 	 */
-	public File postProcess(File input, File workingDirectory);
+	public File postProcess(File input, File workingDirectory, List containers);
 	
 	/**
 	 * Return the name of this process step
@@ -56,6 +59,7 @@
 	 * Adjust any properties in the eclipse.inf as appropriate for this step
 	 * @param input
 	 * @param inf
+	 * @param containers: inf properties for containing jars, innermost jar is first on the list
 	 */
-	public void adjustInf(File input, Properties inf);
+	public void adjustInf(File input, Properties inf, List containers);
 }
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessor.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessor.java
index 2d1966f..d1f759c 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessor.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/JarProcessor.java
@@ -24,6 +24,7 @@
 	private int depth = -1;
 	private boolean verbose = false;
 	private boolean processAll = false;
+	private LinkedList containingInfs = new LinkedList();
 
 	static public JarProcessor getUnpackProcessor(Properties properties) {
 		if (!canPerformUnpack())
@@ -54,7 +55,8 @@
 	}
 
 	public void setWorkingDirectory(String dir) {
-		workingDirectory = dir;
+		if(dir != null)
+			workingDirectory = dir;
 	}
 	
 	public void setVerbose(boolean verbose) {
@@ -169,7 +171,21 @@
 		return result;
 	}
 
-	private void extractEntries(JarFile jar, File tempDir, Map data) throws IOException {
+	private void extractEntries(JarFile jar, File tempDir, Map data, Properties inf) throws IOException {
+		if(inf != null ) {
+			//skip if excluding children
+			if(inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN)){
+				String excludeChildren = inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN);
+				if( Boolean.valueOf(excludeChildren).booleanValue() )
+					if(verbose){
+						for(int i = 0; i <= depth; i++)
+							System.out.print("  "); //$NON-NLS-1$
+						System.out.println("Children of " + jar.getName() + "are excluded from processing.");
+					}
+					return;
+			}
+		}
+		
 		Enumeration entries = jar.entries();
 		if (entries.hasMoreElements()) {
 			for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
@@ -201,10 +217,12 @@
 					data.put(name, newName);
 
 					//recurse
+					containingInfs.addFirst(inf);
 					String dir = getWorkingDirectory();
 					setWorkingDirectory(parentDir.getCanonicalPath());
 					processJar(extracted);
 					setWorkingDirectory(dir);
+					containingInfs.removeFirst();
 
 					//delete the extracted item leaving the recursion result
 					if (!name.equals(newName))
@@ -218,7 +236,7 @@
 		File result = null;
 		for (Iterator iter = steps.iterator(); iter.hasNext();) {
 			IProcessStep step = (IProcessStep) iter.next();
-			result = step.preProcess(input, tempDir);
+			result = step.preProcess(input, tempDir, containingInfs);
 			if (result != null)
 				input = result;
 		}
@@ -229,7 +247,7 @@
 		File result = null;
 		for (Iterator iter = steps.iterator(); iter.hasNext();) {
 			IProcessStep step = (IProcessStep) iter.next();
-			result = step.postProcess(input, tempDir);
+			result = step.postProcess(input, tempDir, containingInfs);
 			if (result != null)
 				input = result;
 		}
@@ -239,7 +257,7 @@
 	private void adjustInf(File input, Properties inf) {
 		for (Iterator iter = steps.iterator(); iter.hasNext();) {
 			IProcessStep step = (IProcessStep) iter.next();
-			step.adjustInf(input, inf);
+			step.adjustInf(input, inf, containingInfs);
 		}
 	}
 
@@ -284,9 +302,9 @@
 
 		JarFile jar = new JarFile(workingFile, false);
 		Map replacements = new HashMap();
-		extractEntries(jar, tempDir, replacements);
+		Properties inf = Utils.getEclipseInf(workingFile, verbose);
+		extractEntries(jar, tempDir, replacements, inf);
 
-		Properties inf = Utils.getEclipseInf(workingFile);
 		if (inf != null)
 			adjustInf(workingFile, inf);
 
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Main.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Main.java
index 7fd4446..2af5bd3 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Main.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Main.java
@@ -11,6 +11,7 @@
 package org.eclipse.update.internal.jarprocessor;
 
 import java.io.*;
+import java.util.Properties;
 import java.util.zip.ZipException;
 
 /**
@@ -110,7 +111,7 @@
 	}
 
 	public static void runJarProcessor(Options options) {
-		if (options.input.getName().endsWith(".zip")) { //$NON-NLS-1$
+		if (options.input.isFile() && options.input.getName().endsWith(".zip")) { //$NON-NLS-1$
 			ZipProcessor processor = new ZipProcessor();
 			processor.setWorkingDirectory(options.outputDir);
 			processor.setSignCommand(options.signCommand);
@@ -134,16 +135,34 @@
 			processor.setProcessAll(options.processAll);
 			processor.setVerbose(options.verbose);
 
+			//load options file
+			Properties properties = null;
+			if(options.input.isDirectory()){
+				File packProperties  = new File(options.input, "pack.properties");
+				if(packProperties.exists() && packProperties.isFile()){
+					InputStream in = null;
+					try {
+						in = new BufferedInputStream( new FileInputStream(packProperties));
+						properties.load(in);
+					} catch (IOException e) {
+						if(options.verbose)
+							e.printStackTrace();
+					} finally {
+						Utils.close(in);
+					}
+				}
+			}
+			
 			if (options.repack || (options.pack && options.signCommand != null))
-				processor.addProcessStep(new PackUnpackStep(null, options.verbose));
+				processor.addProcessStep(new PackUnpackStep(properties, options.verbose));
 
 			if (options.signCommand != null)
-				processor.addProcessStep(new SignCommandStep(null, options.signCommand, options.verbose));
+				processor.addProcessStep(new SignCommandStep(properties, options.signCommand, options.verbose));
 
 			if (options.pack)
-				processor.addProcessStep(new PackStep(null, options.verbose));
+				processor.addProcessStep(new PackStep(properties, options.verbose));
 			else if (options.unpack)
-				processor.addProcessStep(new UnpackStep(null, options.verbose));
+				processor.addProcessStep(new UnpackStep(properties, options.verbose));
 
 			try {
 				processor.process(options.input, options.unpack ? Utils.PACK_GZ_FILTER : Utils.JAR_FILTER);
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackStep.java
index cb2e7b9..4c82822 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackStep.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackStep.java
@@ -12,13 +12,18 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
 
 public class PackStep extends CommandStep {
 
 	protected static String packCommand = null;
 	private static Boolean canPack = null;
 
+	private String arguments = null;
 	private Set exclusions = Collections.EMPTY_SET;
 
 	public static boolean canPack() {
@@ -65,21 +70,18 @@
 		return null;
 	}
 
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
-	public File postProcess(File input, File workingDirectory) {
+	public File postProcess(File input, File workingDirectory, List containers) {
 		if (canPack() && packCommand != null) {
-			Properties inf = Utils.getEclipseInf(input);
-			if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
-				if(verbose)
-					System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+			Properties inf = Utils.getEclipseInf(input, verbose);
+			if (!shouldPack(input, containers, inf))
 				return null;
-			}
 			File outputFile = new File(workingDirectory, input.getName() + Utils.PACKED_SUFFIX);
 			try {
-				String[] cmd = getCommand(input, outputFile, inf);
+				String[] cmd = getCommand(input, outputFile, inf, containers);
 				int result = execute(cmd, verbose);
 				if (result != 0 && verbose)
 					System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
@@ -93,14 +95,34 @@
 		return null;
 	}
 
-	protected String[] getCommand(File input, File outputFile, Properties inf) throws IOException {
-		String[] cmd = null;
-		String arguments = null;
-		if (inf != null && inf.containsKey(Utils.PACK_ARGS)) {
-			arguments = inf.getProperty(Utils.PACK_ARGS);
-		} else {
-			arguments = getOptions().getProperty(input.getName() + ".pack.args"); //$NON-NLS-1$
+	protected boolean shouldPack(File input, List containers, Properties inf) {
+		//1: exclude by containers
+		// innermost jar is first on the list, it can override outer jars
+		for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+			Properties container = (Properties) iterator.next();
+			if (container.containsKey(Utils.MARK_EXCLUDE_CHILDREN_PACK)) {
+				if (Boolean.valueOf(container.getProperty(Utils.MARK_EXCLUDE_CHILDREN_PACK)).booleanValue()) {
+					if (verbose)
+						System.out.println(input.getName() + "is excluded from pack200 by its containers.");
+					return false;
+				}
+				break;
+			}
 		}
+
+		//2: excluded by self
+		if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
+			if (verbose)
+				System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+			return false;
+		}
+
+		return true;
+	}
+
+	protected String[] getCommand(File input, File outputFile, Properties inf, List containers) throws IOException {
+		String[] cmd = null;
+		String arguments = getArguments(input, inf, containers);
 		if (arguments != null && arguments.length() > 0) {
 			String[] args = Utils.toStringArray(arguments, ","); //$NON-NLS-1$
 			cmd = new String[3 + args.length];
@@ -114,23 +136,67 @@
 		return cmd;
 	}
 
+	protected String getArguments(File input, Properties inf, List containers) {
+		if (arguments != null)
+			return arguments;
+		//1: Explicitly marked in our .inf file
+		if (inf != null && inf.containsKey(Utils.PACK_ARGS)) {
+			arguments = inf.getProperty(Utils.PACK_ARGS);
+			return arguments;
+		}
+
+		//2: Defaults set in one of our containing jars
+		for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+			Properties container = (Properties) iterator.next();
+			if (container.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+				arguments = container.getProperty(Utils.DEFAULT_PACK_ARGS);
+				return arguments;
+			}
+		}
+
+		//3: Set by name in outside pack.properties file
+		Properties options = getOptions();
+		String argsKey = input.getName() + Utils.PACK_ARGS_SUFFIX;
+		if (options.containsKey(argsKey)) {
+			arguments = options.getProperty(argsKey);
+			return arguments;
+		}
+
+		//4: Set by default in outside pack.properties file
+		if (options.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+			arguments = options.getProperty(Utils.DEFAULT_PACK_ARGS);
+			return arguments;
+		}
+
+		if (arguments == null)
+			arguments = "";
+		return arguments;
+	}
+
 	public String getStepName() {
 		return "Pack"; //$NON-NLS-1$
 	}
-	
-	public void adjustInf(File input, Properties inf) {
+
+	public void adjustInf(File input, Properties inf, List containers) {
 		if (input == null || inf == null)
 			return;
 
-		if (inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
+		//don't be verbose to check if we should mark the inf
+		boolean v = verbose;
+		verbose = false;
+		if (!shouldPack(input, containers, inf)) {
+			verbose = v;
 			return;
 		}
 
+		//mark as conditioned
 		inf.put(Utils.MARK_PROPERTY, "true"); //$NON-NLS-1$
+
+		//record arguments used
 		String arguments = inf.getProperty(Utils.PACK_ARGS);
 		if (arguments == null) {
-			arguments = getOptions().getProperty(input.getName() + ".pack.args"); //$NON-NLS-1$
-			if (arguments != null)
+			arguments = getArguments(input, inf, containers);
+			if (arguments != null && arguments.length() > 0)
 				inf.put(Utils.PACK_ARGS, arguments);
 		}
 	}
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
index 5e719bb..e413a2a 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
@@ -12,6 +12,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 
@@ -40,19 +41,16 @@
 	}
 
 	/* (non-Javadoc)
-	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
+	 * @see org.eclipse.update.internal.jarprocessor.PackStep#postProcess(java.io.File, java.io.File, java.util.LinkedList)
 	 */
-	public File postProcess(File input, File workingDirectory) {
+	public File postProcess(File input, File workingDirectory, List containers) {
 		if (canPack() && packCommand != null) {
-			Properties inf = Utils.getEclipseInf(input);
-			if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
-				if (verbose)
-					System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+			Properties inf = Utils.getEclipseInf(input, verbose);
+			if (!shouldPack(input, containers, inf))
 				return null;
-			}
 			File tempFile = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
 			try {
-				String[] tmp = getCommand(input, tempFile, inf);
+				String[] tmp = getCommand(input, tempFile, inf, containers);
 				String[] cmd = new String[tmp.length + 1];
 				cmd[0] = tmp[0];
 				cmd[1] = "-r"; //$NON-NLS-1$
@@ -78,9 +76,9 @@
 	}
 
 	/* (non-Javadoc)
-	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
+	 * @see org.eclipse.update.internal.jarprocessor.PackStep#preProcess(java.io.File, java.io.File, java.util.LinkedList)
 	 */
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/SignCommandStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
index 135aa53..310a4a5 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
@@ -10,9 +10,20 @@
  *******************************************************************************/
 package org.eclipse.update.internal.jarprocessor;
 
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
 
 /**
  * @author aniefer@ca.ibm.com
@@ -43,21 +54,15 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
 	 */
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
 	 */
-	public File postProcess(File input, File workingDirectory) {
-		if (command != null) {
-			Properties inf = Utils.getEclipseInf(input);
-			if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_SIGN) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_SIGN)).booleanValue()) {
-				if(verbose)
-					System.out.println("Excluding " + input.getName() + " from signing."); //$NON-NLS-1$ //$NON-NLS-2$
-				return null;
-			}
+	public File postProcess(File input, File workingDirectory, List containers) {
+		if (command != null && shouldSign(input, containers)) {
 			try {
 				String[] cmd = new String[] {command, input.getCanonicalPath()};
 				int result = execute(cmd, verbose);
@@ -76,6 +81,33 @@
 		return null;
 	}
 
+	private boolean shouldSign(File input, List containers) {
+		Properties inf = null;
+
+		//1: Are we excluded from signing by our parents?
+		//innermost jar is first on the list, it overrides outer jars
+		for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+			inf = (Properties) iterator.next();
+			if (inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN_SIGN)){
+				if(Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN_SIGN)).booleanValue()) {
+					if (verbose)
+						System.out.println(input.getName() + "is excluded from signing by its containers."); //$NON-NLS-1$ //$NON-NLS-2$
+					return false;
+				}
+				break;
+			}
+		}
+
+		//2: Is this jar itself marked as exclude?
+		inf = Utils.getEclipseInf(input, verbose);
+		if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_SIGN) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_SIGN)).booleanValue()) {
+			if (verbose)
+				System.out.println("Excluding " + input.getName() + " from signing."); //$NON-NLS-1$ //$NON-NLS-2$
+			return false;
+		}
+		return true;
+	}
+
 	private void normalize(File input, File workingDirectory) {
 		try {
 			File tempJar = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/UnpackStep.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/UnpackStep.java
index f8937ca..1d30dd8 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/UnpackStep.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/UnpackStep.java
@@ -12,6 +12,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 import java.util.Properties;
 
 /**
@@ -71,7 +72,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
 	 */
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		if (canUnpack() && unpackCommand != null) {
 			String name = input.getName();
 			if (name.endsWith(Utils.PACKED_SUFFIX)) {
@@ -106,7 +107,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
 	 */
-	public File postProcess(File input, File workingDirectory) {
+	public File postProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
diff --git a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Utils.java b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Utils.java
index 6ed9a18..11490ed 100644
--- a/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Utils.java
+++ b/update/org.eclipse.update.core/jarprocessor/org/eclipse/update/internal/jarprocessor/Utils.java
@@ -19,16 +19,45 @@
  *
  */
 public class Utils {
-	public static final String SIGN_EXCLUDES = "sign.excludes"; //$NON-NLS-1$
-	public static final String PACK_EXCLUDES = "pack.excludes"; //$NON-NLS-1$
 	public static final String MARK_FILE_NAME = "META-INF/eclipse.inf"; //$NON-NLS-1$
+	
+	/*
+	 * Properties found in outer pack.properties file
+	 */
+	//comma separated list of jars to exclude from sigining
+	public static final String SIGN_EXCLUDES = "sign.excludes"; //$NON-NLS-1$
+	//comma separated list of jars to exlclude from packing
+	public static final String PACK_EXCLUDES = "pack.excludes"; //$NON-NLS-1$
+	//Suffix used when specifying arguments to use when running pack200 on a jar
+	public static final String PACK_ARGS_SUFFIX = ".pack.args"; //$NON-NLS-1$
+	
+	/*
+	 * Properties found in both pack.properties and eclipse.inf
+	 */
+	//	Default arguments to use when running pack200.
+	// Affects all jars when specified in pack.properties, affects children when specified in eclipse.inf
+	public static final String DEFAULT_PACK_ARGS = "pack200.default.args"; //$NON-NLS-1$
+	
+	/*
+	 * Properties found in eclipse.inf file
+	 */
+	//This jar has been conditioned with pack200
 	public static final String MARK_PROPERTY = "pack200.conditioned"; //$NON-NLS-1$
+	//Exclude this jar from processing
 	public static final String MARK_EXCLUDE = "jarprocessor.exclude"; //$NON-NLS-1$
+	//Exclude this jar from pack200
 	public static final String MARK_EXCLUDE_PACK = "jarprocessor.exclude.pack"; //$NON-NLS-1$
+	//Exclude this jar from signing
 	public static final String MARK_EXCLUDE_SIGN = "jarprocessor.exclude.sign"; //$NON-NLS-1$
-	public static final String MARK_JARPROCESSOR_VERSION = "jarprocessor.version"; //$NON-NLS-1$
+	//Exclude this jar's children from processing
+	public static final String MARK_EXCLUDE_CHILDREN = "jarprocessor.exclude.children";
+	//Exclude this jar's children from pack200
+	public static final String MARK_EXCLUDE_CHILDREN_PACK = "jarprocessor.exclude.children.pack";
+	//Exclude this jar's children from signing
+	public static final String MARK_EXCLUDE_CHILDREN_SIGN = "jarprocessor.exclude.children.sign";
+	//Arguments used in pack200 for this jar
 	public static final String PACK_ARGS = "pack200.args"; //$NON-NLS-1$
-
+	
 	public static final String PACK200_PROPERTY = "org.eclipse.update.jarprocessor.pack200"; //$NON-NLS-1$
 	public static final String JRE = "@jre"; //$NON-NLS-1$
 	public static final String PATH = "@path"; //$NON-NLS-1$
@@ -185,11 +214,11 @@
 		}
 		return Collections.EMPTY_SET;
 	}
-	
-	public static String concat(String [] array){
+
+	public static String concat(String[] array) {
 		StringBuffer buffer = new StringBuffer();
 		for (int i = 0; i < array.length; i++) {
-			if( i > 0 )
+			if (i > 0)
 				buffer.append(' ');
 			buffer.append(array[i]);
 		}
@@ -210,12 +239,14 @@
 	 * Get the properties from the eclipse.inf file from the given jar.  If the file is not a jar, null is returned.
 	 * If the file is a jar, but does not contain an eclipse.inf file, an empty Properties object is returned.
 	 * @param jarFile
-	 * @return
+	 * @return The eclipse.inf properties for the given jar file
 	 */
-	public static Properties getEclipseInf(File jarFile) {
-		if (jarFile == null || !jarFile.exists())
+	public static Properties getEclipseInf(File jarFile, boolean verbose) {
+		if (jarFile == null || !jarFile.exists()) {
+			if (verbose)
+				System.out.println("Failed to obtain eclipse.inf due to missing jar file: " + jarFile);
 			return null;
-
+		}
 		JarFile jar = null;
 		try {
 			jar = new JarFile(jarFile, false);
@@ -229,15 +260,19 @@
 			}
 			return new Properties();
 		} catch (IOException e) {
+			if (verbose) {
+				System.out.println("Failed to obtain eclipse.inf due to IOException: " + jarFile);
+				e.printStackTrace();
+			}
 			//not a jar
+			return null;
 		} finally {
 			close(jar);
 		}
-		return null;
 	}
 
 	public static boolean shouldSkipJar(File input, boolean processAll, boolean verbose) {
-		Properties inf = getEclipseInf(input);
+		Properties inf = getEclipseInf(input, verbose);
 		if (inf == null) {
 			//not a jar, could be a pack.gz
 			return false;
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/CommandStep.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/CommandStep.java
index 680607f..4180d28 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/CommandStep.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/CommandStep.java
@@ -11,6 +11,7 @@
 package org.eclipse.update.internal.jarprocessor;
 
 import java.io.File;
+import java.util.List;
 import java.util.Properties;
 
 /**
@@ -62,7 +63,7 @@
 		return options;
 	}
 	
-	public void adjustInf(File input, Properties inf) {
+	public void adjustInf(File input, Properties inf, List containers) {
 		//nothing
 	}
 }
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/IProcessStep.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/IProcessStep.java
index 20d4500..18c438e 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/IProcessStep.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/IProcessStep.java
@@ -11,6 +11,7 @@
 package org.eclipse.update.internal.jarprocessor;
 
 import java.io.File;
+import java.util.List;
 import java.util.Properties;
 
 /**
@@ -33,18 +34,20 @@
 	 *  return the file containing the result of the processing
 	 * @param input
 	 * @param workingDirectory
+	 * @param containers: inf properties for containing jars, innermost jar is first on the list
 	 * @return
 	 */
-	public File preProcess(File input, File workingDirectory);
+	public File preProcess(File input, File workingDirectory, List containers);
 	
 	/**
 	 * Perform some processing on the input file after the JarProcessor returns from recursion
 	 * return the file containing the result of the processing
 	 * @param input
 	 * @param workingDirectory
+	 * @param containers: inf properties for containing jars, innermost jar is first on the list
 	 * @return
 	 */
-	public File postProcess(File input, File workingDirectory);
+	public File postProcess(File input, File workingDirectory, List containers);
 	
 	/**
 	 * Return the name of this process step
@@ -56,6 +59,7 @@
 	 * Adjust any properties in the eclipse.inf as appropriate for this step
 	 * @param input
 	 * @param inf
+	 * @param containers: inf properties for containing jars, innermost jar is first on the list
 	 */
-	public void adjustInf(File input, Properties inf);
+	public void adjustInf(File input, Properties inf, List containers);
 }
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/JarProcessor.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/JarProcessor.java
index 2d1966f..d1f759c 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/JarProcessor.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/JarProcessor.java
@@ -24,6 +24,7 @@
 	private int depth = -1;
 	private boolean verbose = false;
 	private boolean processAll = false;
+	private LinkedList containingInfs = new LinkedList();
 
 	static public JarProcessor getUnpackProcessor(Properties properties) {
 		if (!canPerformUnpack())
@@ -54,7 +55,8 @@
 	}
 
 	public void setWorkingDirectory(String dir) {
-		workingDirectory = dir;
+		if(dir != null)
+			workingDirectory = dir;
 	}
 	
 	public void setVerbose(boolean verbose) {
@@ -169,7 +171,21 @@
 		return result;
 	}
 
-	private void extractEntries(JarFile jar, File tempDir, Map data) throws IOException {
+	private void extractEntries(JarFile jar, File tempDir, Map data, Properties inf) throws IOException {
+		if(inf != null ) {
+			//skip if excluding children
+			if(inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN)){
+				String excludeChildren = inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN);
+				if( Boolean.valueOf(excludeChildren).booleanValue() )
+					if(verbose){
+						for(int i = 0; i <= depth; i++)
+							System.out.print("  "); //$NON-NLS-1$
+						System.out.println("Children of " + jar.getName() + "are excluded from processing.");
+					}
+					return;
+			}
+		}
+		
 		Enumeration entries = jar.entries();
 		if (entries.hasMoreElements()) {
 			for (JarEntry entry = (JarEntry) entries.nextElement(); entry != null; entry = entries.hasMoreElements() ? (JarEntry) entries.nextElement() : null) {
@@ -201,10 +217,12 @@
 					data.put(name, newName);
 
 					//recurse
+					containingInfs.addFirst(inf);
 					String dir = getWorkingDirectory();
 					setWorkingDirectory(parentDir.getCanonicalPath());
 					processJar(extracted);
 					setWorkingDirectory(dir);
+					containingInfs.removeFirst();
 
 					//delete the extracted item leaving the recursion result
 					if (!name.equals(newName))
@@ -218,7 +236,7 @@
 		File result = null;
 		for (Iterator iter = steps.iterator(); iter.hasNext();) {
 			IProcessStep step = (IProcessStep) iter.next();
-			result = step.preProcess(input, tempDir);
+			result = step.preProcess(input, tempDir, containingInfs);
 			if (result != null)
 				input = result;
 		}
@@ -229,7 +247,7 @@
 		File result = null;
 		for (Iterator iter = steps.iterator(); iter.hasNext();) {
 			IProcessStep step = (IProcessStep) iter.next();
-			result = step.postProcess(input, tempDir);
+			result = step.postProcess(input, tempDir, containingInfs);
 			if (result != null)
 				input = result;
 		}
@@ -239,7 +257,7 @@
 	private void adjustInf(File input, Properties inf) {
 		for (Iterator iter = steps.iterator(); iter.hasNext();) {
 			IProcessStep step = (IProcessStep) iter.next();
-			step.adjustInf(input, inf);
+			step.adjustInf(input, inf, containingInfs);
 		}
 	}
 
@@ -284,9 +302,9 @@
 
 		JarFile jar = new JarFile(workingFile, false);
 		Map replacements = new HashMap();
-		extractEntries(jar, tempDir, replacements);
+		Properties inf = Utils.getEclipseInf(workingFile, verbose);
+		extractEntries(jar, tempDir, replacements, inf);
 
-		Properties inf = Utils.getEclipseInf(workingFile);
 		if (inf != null)
 			adjustInf(workingFile, inf);
 
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Main.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Main.java
index 7fd4446..2af5bd3 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Main.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Main.java
@@ -11,6 +11,7 @@
 package org.eclipse.update.internal.jarprocessor;
 
 import java.io.*;
+import java.util.Properties;
 import java.util.zip.ZipException;
 
 /**
@@ -110,7 +111,7 @@
 	}
 
 	public static void runJarProcessor(Options options) {
-		if (options.input.getName().endsWith(".zip")) { //$NON-NLS-1$
+		if (options.input.isFile() && options.input.getName().endsWith(".zip")) { //$NON-NLS-1$
 			ZipProcessor processor = new ZipProcessor();
 			processor.setWorkingDirectory(options.outputDir);
 			processor.setSignCommand(options.signCommand);
@@ -134,16 +135,34 @@
 			processor.setProcessAll(options.processAll);
 			processor.setVerbose(options.verbose);
 
+			//load options file
+			Properties properties = null;
+			if(options.input.isDirectory()){
+				File packProperties  = new File(options.input, "pack.properties");
+				if(packProperties.exists() && packProperties.isFile()){
+					InputStream in = null;
+					try {
+						in = new BufferedInputStream( new FileInputStream(packProperties));
+						properties.load(in);
+					} catch (IOException e) {
+						if(options.verbose)
+							e.printStackTrace();
+					} finally {
+						Utils.close(in);
+					}
+				}
+			}
+			
 			if (options.repack || (options.pack && options.signCommand != null))
-				processor.addProcessStep(new PackUnpackStep(null, options.verbose));
+				processor.addProcessStep(new PackUnpackStep(properties, options.verbose));
 
 			if (options.signCommand != null)
-				processor.addProcessStep(new SignCommandStep(null, options.signCommand, options.verbose));
+				processor.addProcessStep(new SignCommandStep(properties, options.signCommand, options.verbose));
 
 			if (options.pack)
-				processor.addProcessStep(new PackStep(null, options.verbose));
+				processor.addProcessStep(new PackStep(properties, options.verbose));
 			else if (options.unpack)
-				processor.addProcessStep(new UnpackStep(null, options.verbose));
+				processor.addProcessStep(new UnpackStep(properties, options.verbose));
 
 			try {
 				processor.process(options.input, options.unpack ? Utils.PACK_GZ_FILTER : Utils.JAR_FILTER);
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackStep.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackStep.java
index cb2e7b9..4c82822 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackStep.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackStep.java
@@ -12,13 +12,18 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
 
 public class PackStep extends CommandStep {
 
 	protected static String packCommand = null;
 	private static Boolean canPack = null;
 
+	private String arguments = null;
 	private Set exclusions = Collections.EMPTY_SET;
 
 	public static boolean canPack() {
@@ -65,21 +70,18 @@
 		return null;
 	}
 
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
-	public File postProcess(File input, File workingDirectory) {
+	public File postProcess(File input, File workingDirectory, List containers) {
 		if (canPack() && packCommand != null) {
-			Properties inf = Utils.getEclipseInf(input);
-			if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
-				if(verbose)
-					System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+			Properties inf = Utils.getEclipseInf(input, verbose);
+			if (!shouldPack(input, containers, inf))
 				return null;
-			}
 			File outputFile = new File(workingDirectory, input.getName() + Utils.PACKED_SUFFIX);
 			try {
-				String[] cmd = getCommand(input, outputFile, inf);
+				String[] cmd = getCommand(input, outputFile, inf, containers);
 				int result = execute(cmd, verbose);
 				if (result != 0 && verbose)
 					System.out.println("Error: " + result + " was returned from command: " + Utils.concat(cmd)); //$NON-NLS-1$ //$NON-NLS-2$
@@ -93,14 +95,34 @@
 		return null;
 	}
 
-	protected String[] getCommand(File input, File outputFile, Properties inf) throws IOException {
-		String[] cmd = null;
-		String arguments = null;
-		if (inf != null && inf.containsKey(Utils.PACK_ARGS)) {
-			arguments = inf.getProperty(Utils.PACK_ARGS);
-		} else {
-			arguments = getOptions().getProperty(input.getName() + ".pack.args"); //$NON-NLS-1$
+	protected boolean shouldPack(File input, List containers, Properties inf) {
+		//1: exclude by containers
+		// innermost jar is first on the list, it can override outer jars
+		for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+			Properties container = (Properties) iterator.next();
+			if (container.containsKey(Utils.MARK_EXCLUDE_CHILDREN_PACK)) {
+				if (Boolean.valueOf(container.getProperty(Utils.MARK_EXCLUDE_CHILDREN_PACK)).booleanValue()) {
+					if (verbose)
+						System.out.println(input.getName() + "is excluded from pack200 by its containers.");
+					return false;
+				}
+				break;
+			}
 		}
+
+		//2: excluded by self
+		if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
+			if (verbose)
+				System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+			return false;
+		}
+
+		return true;
+	}
+
+	protected String[] getCommand(File input, File outputFile, Properties inf, List containers) throws IOException {
+		String[] cmd = null;
+		String arguments = getArguments(input, inf, containers);
 		if (arguments != null && arguments.length() > 0) {
 			String[] args = Utils.toStringArray(arguments, ","); //$NON-NLS-1$
 			cmd = new String[3 + args.length];
@@ -114,23 +136,67 @@
 		return cmd;
 	}
 
+	protected String getArguments(File input, Properties inf, List containers) {
+		if (arguments != null)
+			return arguments;
+		//1: Explicitly marked in our .inf file
+		if (inf != null && inf.containsKey(Utils.PACK_ARGS)) {
+			arguments = inf.getProperty(Utils.PACK_ARGS);
+			return arguments;
+		}
+
+		//2: Defaults set in one of our containing jars
+		for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+			Properties container = (Properties) iterator.next();
+			if (container.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+				arguments = container.getProperty(Utils.DEFAULT_PACK_ARGS);
+				return arguments;
+			}
+		}
+
+		//3: Set by name in outside pack.properties file
+		Properties options = getOptions();
+		String argsKey = input.getName() + Utils.PACK_ARGS_SUFFIX;
+		if (options.containsKey(argsKey)) {
+			arguments = options.getProperty(argsKey);
+			return arguments;
+		}
+
+		//4: Set by default in outside pack.properties file
+		if (options.containsKey(Utils.DEFAULT_PACK_ARGS)) {
+			arguments = options.getProperty(Utils.DEFAULT_PACK_ARGS);
+			return arguments;
+		}
+
+		if (arguments == null)
+			arguments = "";
+		return arguments;
+	}
+
 	public String getStepName() {
 		return "Pack"; //$NON-NLS-1$
 	}
-	
-	public void adjustInf(File input, Properties inf) {
+
+	public void adjustInf(File input, Properties inf, List containers) {
 		if (input == null || inf == null)
 			return;
 
-		if (inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
+		//don't be verbose to check if we should mark the inf
+		boolean v = verbose;
+		verbose = false;
+		if (!shouldPack(input, containers, inf)) {
+			verbose = v;
 			return;
 		}
 
+		//mark as conditioned
 		inf.put(Utils.MARK_PROPERTY, "true"); //$NON-NLS-1$
+
+		//record arguments used
 		String arguments = inf.getProperty(Utils.PACK_ARGS);
 		if (arguments == null) {
-			arguments = getOptions().getProperty(input.getName() + ".pack.args"); //$NON-NLS-1$
-			if (arguments != null)
+			arguments = getArguments(input, inf, containers);
+			if (arguments != null && arguments.length() > 0)
 				inf.put(Utils.PACK_ARGS, arguments);
 		}
 	}
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
index 5e719bb..e413a2a 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/PackUnpackStep.java
@@ -12,6 +12,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 
@@ -40,19 +41,16 @@
 	}
 
 	/* (non-Javadoc)
-	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
+	 * @see org.eclipse.update.internal.jarprocessor.PackStep#postProcess(java.io.File, java.io.File, java.util.LinkedList)
 	 */
-	public File postProcess(File input, File workingDirectory) {
+	public File postProcess(File input, File workingDirectory, List containers) {
 		if (canPack() && packCommand != null) {
-			Properties inf = Utils.getEclipseInf(input);
-			if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_PACK) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_PACK)).booleanValue()) {
-				if (verbose)
-					System.out.println("Excluding " + input.getName() + " from " + getStepName()); //$NON-NLS-1$ //$NON-NLS-2$
+			Properties inf = Utils.getEclipseInf(input, verbose);
+			if (!shouldPack(input, containers, inf))
 				return null;
-			}
 			File tempFile = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
 			try {
-				String[] tmp = getCommand(input, tempFile, inf);
+				String[] tmp = getCommand(input, tempFile, inf, containers);
 				String[] cmd = new String[tmp.length + 1];
 				cmd[0] = tmp[0];
 				cmd[1] = "-r"; //$NON-NLS-1$
@@ -78,9 +76,9 @@
 	}
 
 	/* (non-Javadoc)
-	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
+	 * @see org.eclipse.update.internal.jarprocessor.PackStep#preProcess(java.io.File, java.io.File, java.util.LinkedList)
 	 */
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/SignCommandStep.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
index 135aa53..310a4a5 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/SignCommandStep.java
@@ -10,9 +10,20 @@
  *******************************************************************************/
 package org.eclipse.update.internal.jarprocessor;
 
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
 
 /**
  * @author aniefer@ca.ibm.com
@@ -43,21 +54,15 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
 	 */
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
 	 */
-	public File postProcess(File input, File workingDirectory) {
-		if (command != null) {
-			Properties inf = Utils.getEclipseInf(input);
-			if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_SIGN) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_SIGN)).booleanValue()) {
-				if(verbose)
-					System.out.println("Excluding " + input.getName() + " from signing."); //$NON-NLS-1$ //$NON-NLS-2$
-				return null;
-			}
+	public File postProcess(File input, File workingDirectory, List containers) {
+		if (command != null && shouldSign(input, containers)) {
 			try {
 				String[] cmd = new String[] {command, input.getCanonicalPath()};
 				int result = execute(cmd, verbose);
@@ -76,6 +81,33 @@
 		return null;
 	}
 
+	private boolean shouldSign(File input, List containers) {
+		Properties inf = null;
+
+		//1: Are we excluded from signing by our parents?
+		//innermost jar is first on the list, it overrides outer jars
+		for (Iterator iterator = containers.iterator(); iterator.hasNext();) {
+			inf = (Properties) iterator.next();
+			if (inf.containsKey(Utils.MARK_EXCLUDE_CHILDREN_SIGN)){
+				if(Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_CHILDREN_SIGN)).booleanValue()) {
+					if (verbose)
+						System.out.println(input.getName() + "is excluded from signing by its containers."); //$NON-NLS-1$ //$NON-NLS-2$
+					return false;
+				}
+				break;
+			}
+		}
+
+		//2: Is this jar itself marked as exclude?
+		inf = Utils.getEclipseInf(input, verbose);
+		if (inf != null && inf.containsKey(Utils.MARK_EXCLUDE_SIGN) && Boolean.valueOf(inf.getProperty(Utils.MARK_EXCLUDE_SIGN)).booleanValue()) {
+			if (verbose)
+				System.out.println("Excluding " + input.getName() + " from signing."); //$NON-NLS-1$ //$NON-NLS-2$
+			return false;
+		}
+		return true;
+	}
+
 	private void normalize(File input, File workingDirectory) {
 		try {
 			File tempJar = new File(workingDirectory, "temp_" + input.getName()); //$NON-NLS-1$
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/UnpackStep.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/UnpackStep.java
index f8937ca..1d30dd8 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/UnpackStep.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/UnpackStep.java
@@ -12,6 +12,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 import java.util.Properties;
 
 /**
@@ -71,7 +72,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#preProcess(java.io.File, java.io.File)
 	 */
-	public File preProcess(File input, File workingDirectory) {
+	public File preProcess(File input, File workingDirectory, List containers) {
 		if (canUnpack() && unpackCommand != null) {
 			String name = input.getName();
 			if (name.endsWith(Utils.PACKED_SUFFIX)) {
@@ -106,7 +107,7 @@
 	/* (non-Javadoc)
 	 * @see org.eclipse.update.jarprocessor.IProcessStep#postProcess(java.io.File, java.io.File)
 	 */
-	public File postProcess(File input, File workingDirectory) {
+	public File postProcess(File input, File workingDirectory, List containers) {
 		return null;
 	}
 
diff --git a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Utils.java b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Utils.java
index 6ed9a18..11490ed 100644
--- a/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Utils.java
+++ b/update/org.eclipse.update.core/src/org/eclipse/update/internal/jarprocessor/Utils.java
@@ -19,16 +19,45 @@
  *
  */
 public class Utils {
-	public static final String SIGN_EXCLUDES = "sign.excludes"; //$NON-NLS-1$
-	public static final String PACK_EXCLUDES = "pack.excludes"; //$NON-NLS-1$
 	public static final String MARK_FILE_NAME = "META-INF/eclipse.inf"; //$NON-NLS-1$
+	
+	/*
+	 * Properties found in outer pack.properties file
+	 */
+	//comma separated list of jars to exclude from sigining
+	public static final String SIGN_EXCLUDES = "sign.excludes"; //$NON-NLS-1$
+	//comma separated list of jars to exlclude from packing
+	public static final String PACK_EXCLUDES = "pack.excludes"; //$NON-NLS-1$
+	//Suffix used when specifying arguments to use when running pack200 on a jar
+	public static final String PACK_ARGS_SUFFIX = ".pack.args"; //$NON-NLS-1$
+	
+	/*
+	 * Properties found in both pack.properties and eclipse.inf
+	 */
+	//	Default arguments to use when running pack200.
+	// Affects all jars when specified in pack.properties, affects children when specified in eclipse.inf
+	public static final String DEFAULT_PACK_ARGS = "pack200.default.args"; //$NON-NLS-1$
+	
+	/*
+	 * Properties found in eclipse.inf file
+	 */
+	//This jar has been conditioned with pack200
 	public static final String MARK_PROPERTY = "pack200.conditioned"; //$NON-NLS-1$
+	//Exclude this jar from processing
 	public static final String MARK_EXCLUDE = "jarprocessor.exclude"; //$NON-NLS-1$
+	//Exclude this jar from pack200
 	public static final String MARK_EXCLUDE_PACK = "jarprocessor.exclude.pack"; //$NON-NLS-1$
+	//Exclude this jar from signing
 	public static final String MARK_EXCLUDE_SIGN = "jarprocessor.exclude.sign"; //$NON-NLS-1$
-	public static final String MARK_JARPROCESSOR_VERSION = "jarprocessor.version"; //$NON-NLS-1$
+	//Exclude this jar's children from processing
+	public static final String MARK_EXCLUDE_CHILDREN = "jarprocessor.exclude.children";
+	//Exclude this jar's children from pack200
+	public static final String MARK_EXCLUDE_CHILDREN_PACK = "jarprocessor.exclude.children.pack";
+	//Exclude this jar's children from signing
+	public static final String MARK_EXCLUDE_CHILDREN_SIGN = "jarprocessor.exclude.children.sign";
+	//Arguments used in pack200 for this jar
 	public static final String PACK_ARGS = "pack200.args"; //$NON-NLS-1$
-
+	
 	public static final String PACK200_PROPERTY = "org.eclipse.update.jarprocessor.pack200"; //$NON-NLS-1$
 	public static final String JRE = "@jre"; //$NON-NLS-1$
 	public static final String PATH = "@path"; //$NON-NLS-1$
@@ -185,11 +214,11 @@
 		}
 		return Collections.EMPTY_SET;
 	}
-	
-	public static String concat(String [] array){
+
+	public static String concat(String[] array) {
 		StringBuffer buffer = new StringBuffer();
 		for (int i = 0; i < array.length; i++) {
-			if( i > 0 )
+			if (i > 0)
 				buffer.append(' ');
 			buffer.append(array[i]);
 		}
@@ -210,12 +239,14 @@
 	 * Get the properties from the eclipse.inf file from the given jar.  If the file is not a jar, null is returned.
 	 * If the file is a jar, but does not contain an eclipse.inf file, an empty Properties object is returned.
 	 * @param jarFile
-	 * @return
+	 * @return The eclipse.inf properties for the given jar file
 	 */
-	public static Properties getEclipseInf(File jarFile) {
-		if (jarFile == null || !jarFile.exists())
+	public static Properties getEclipseInf(File jarFile, boolean verbose) {
+		if (jarFile == null || !jarFile.exists()) {
+			if (verbose)
+				System.out.println("Failed to obtain eclipse.inf due to missing jar file: " + jarFile);
 			return null;
-
+		}
 		JarFile jar = null;
 		try {
 			jar = new JarFile(jarFile, false);
@@ -229,15 +260,19 @@
 			}
 			return new Properties();
 		} catch (IOException e) {
+			if (verbose) {
+				System.out.println("Failed to obtain eclipse.inf due to IOException: " + jarFile);
+				e.printStackTrace();
+			}
 			//not a jar
+			return null;
 		} finally {
 			close(jar);
 		}
-		return null;
 	}
 
 	public static boolean shouldSkipJar(File input, boolean processAll, boolean verbose) {
-		Properties inf = getEclipseInf(input);
+		Properties inf = getEclipseInf(input, verbose);
 		if (inf == null) {
 			//not a jar, could be a pack.gz
 			return false;