[323174] Existence of classpath dependencies should not break single-root
diff --git a/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/AllTests.java b/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/AllTests.java
index b7cdc7a..3fee11e 100644
--- a/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/AllTests.java
+++ b/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/AllTests.java
@@ -22,8 +22,7 @@
         suite.addTest(ClasspathDependencyCreationTests.suite());
         //suite.addTest(ClasspathDependencyValidationTests.suite());
         suite.addTest(ClasspathDependencyEARTests.suite());
-        //[Bug 234409] Temporarily removing these tests until underlying issue is fixed
-//        suite.addTest(ClasspathDependencyWebTests.suite());
+        suite.addTest(ClasspathDependencyWebTests.suite());
         
         return suite;
     }
diff --git a/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyEARTests.java b/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyEARTests.java
index 2a6adc9..adb15ed 100644
--- a/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyEARTests.java
+++ b/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyEARTests.java
@@ -70,6 +70,7 @@
         //suite.addTest(new ClasspathDependencyEARTests("testEARExportJEE5"));
         suite.addTest(new ClasspathDependencyEARTests("testEARPublishJ2EE"));
         suite.addTest(new ClasspathDependencyEARTests("testEARPublishJEE5"));
+        suite.addTest(new ClasspathDependencyEARTests("testEARLibPublishJEE5"));
         return suite;
     }
     
@@ -189,6 +190,10 @@
     	testEARPublish(true);
     }
     
+    public void testEARLibPublishJEE5() throws Exception {
+    	testEARLibPublishJEE5(true);
+    }
+    
     private void testEARPublish(boolean JEE5) throws Exception {
 
     	// create the EAR and module projects
@@ -214,19 +219,41 @@
     	verifyPublishedEAR(earComp, archiveNames, true, JEE5);
     }
     
+    private void testEARLibPublishJEE5(boolean JEE5) throws Exception {
+    	IVirtualComponent webComp = createWebProject(JEE5);
+    	
+    	final Set archiveNames = new HashSet();
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST1_JAR);
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST2_JAR);
+    	final IProject earProject = ProjectUtil.getProject(EAR_PROJECT);
+    	final IVirtualComponent earComp = ComponentCore.createComponent(earProject);
+    	
+    	verifyPublishedEARLibRef(earComp, archiveNames, false, JEE5);
+
+    	addEARLibDependencyAttribute(false);
+    	
+    	verifyPublishedEARLibRef(earComp, archiveNames, true, JEE5);
+    }
+    
     private void verifyPublishedEAR(final IVirtualComponent comp, final Set archiveNames, final boolean shouldHaveDependencies, boolean isEE5) throws Exception {
     	
     	// verify that the published EAR contains the cp container jars from the Utility
     	J2EEFlexProjDeployable deployable = new J2EEFlexProjDeployable(comp.getProject(), comp);
 		try {
 			IModuleResource[] rootmembers = deployable.members();
-			IModuleResource[] members;
-			if (isEE5 && rootmembers.length > 0 && rootmembers[0].getName().equals("lib")) {
-				members = ((IModuleFolder) rootmembers[0]).members();
+			IModuleResource[] members = null;
+			if (isEE5) {
+				for (int i=0; i<rootmembers.length; i++) {
+					String name = rootmembers[i].getName();
+					if (name.equals("lib")) {
+						members = ((IModuleFolder)rootmembers[i]).members();
+					}
+				}
 			}
-			else {
+
+			if (members == null)
 				members = rootmembers;
-			}
+				
 			Iterator it = archiveNames.iterator();						
 			while (it.hasNext()) {
 				String name = (String) it.next();
@@ -354,6 +381,105 @@
 		}    	
     }
     
+private void verifyPublishedEARLibRef(final IVirtualComponent comp, final Set archiveNames, final boolean shouldHaveDependencies, boolean isEE5) throws Exception {
+    	
+    	J2EEFlexProjDeployable deployable = new J2EEFlexProjDeployable(comp.getProject(), comp);
+		try {
+			IModuleResource[] rootmembers = deployable.members();
+			IModuleResource[] members = null;
+			if (isEE5) {
+				for (int i=0; i<rootmembers.length; i++) {
+					String name = rootmembers[i].getName();
+					if (name.equals("lib")) {
+						members = ((IModuleFolder)rootmembers[i]).members();
+					}
+				}
+			}
+
+			if (members == null)
+				members = rootmembers;
+			
+			Iterator it = archiveNames.iterator();						
+			while (it.hasNext()) {
+				String name = (String) it.next();
+				boolean hasArchive = false;
+				for (int i=0; i<members.length; i++) {
+					if (members[i].getName().equals(name)) {
+						hasArchive = true;
+					}
+				}
+				if (shouldHaveDependencies) {
+					assertTrue("Published EAR missing classpath dependency Jar " + name, hasArchive);  					
+				} else {
+					assertFalse("Published EAR has unexpected classpath dependency Jar " + name, hasArchive);
+				}
+			}
+			
+			IModule webModule = null;
+			IModule[] childModules = deployable.getChildModules();
+			for (int i=0; i < childModules.length; i++) {
+				if (childModules[i].getName().equals(WEB_PROJECT)) {
+					webModule = childModules[i];
+				}
+			}
+			
+			assertNotNull("Missing entry for web project", webModule);
+
+			J2EEFlexProjDeployable projectModule =(J2EEFlexProjDeployable) webModule.loadAdapter(ProjectModule.class, null);
+			IModuleResource[] moduleMembers = projectModule.members();
+			ArchiveManifest manifest = null;
+			boolean foundMetaInf = false;
+			for (int i=0; i< moduleMembers.length; i++) {
+				String name = moduleMembers[i].getName();
+				if (name.equals("META-INF")) {
+					foundMetaInf = true;
+					IModuleResource manifestResource= ((IModuleFolder)moduleMembers[i]).members()[0];
+					assertTrue(manifestResource.getModuleRelativePath().toString().equals("META-INF"));
+					assertTrue("Expected MANIFEST.MF, got " + manifestResource.getName(), manifestResource.getName().equals("MANIFEST.MF"));
+					java.io.File manifestFile = (java.io.File) manifestResource.getAdapter(java.io.File.class);
+					if (manifestFile == null) {
+						manifestFile = ((IFile) manifestResource.getAdapter(IFile.class)).getLocation().toFile();
+					}
+					assertNotNull(manifestFile);
+					FileInputStream fis = null;
+					try {
+						fis = new FileInputStream(manifestFile);
+						manifest = new ArchiveManifestImpl(fis);
+					} finally {
+						if (fis != null) {
+							fis.close();
+						}
+					}
+				} 
+			}
+			if (!foundMetaInf) {
+				assertTrue("members() failed to return META-INF for web project module in published EAR", foundMetaInf);
+			}
+			
+			assertNotNull("Failed to retrieve MANIFEST.MF from web project module in published EAR", manifest);
+			
+			it = archiveNames.iterator();						
+			while (it.hasNext()) {
+				String name = (String) it.next();
+				boolean isOnCP = false;
+				String[] cp = manifest.getClassPathTokenized();
+				for (int j = 0; j < cp.length; j++) {
+					if (cp[j].equals("lib/" + name)) {
+						isOnCP = true;
+					}
+				}
+				if (shouldHaveDependencies && ClasspathDependencyEnablement.isAllowClasspathComponentDependency()) {
+					assertTrue("Utility project MANIFEST.MF classpath in published EAR missing entry for dependency Jar " + name, isOnCP);  					
+				} else {
+					assertFalse("Utility project MANIFEST.MF classpath in published EAR has unexpected entry for dependency Jar " + name, isOnCP);  					
+				}
+			}
+			
+		} catch (CoreException e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}    	
+    }
     
     private IVirtualComponent createProjects(boolean JEE5) throws Exception {
 
@@ -395,14 +521,29 @@
     	
     	return webComp;
     }
+    
+    private IVirtualComponent createWebProject(boolean JEE5) throws Exception {
+    	// create a Web project
+    	int version = J2EEVersionConstants.SERVLET_2_5;
+    	if (!JEE5) {
+    		version = J2EEVersionConstants.SERVLET_2_4;
+    	}
+    	final IProject webProject = ProjectUtil.createWebProject(WEB_PROJECT, EAR_PROJECT, version, true);
+    	final IJavaProject webJavaProject = JavaCore.create(webProject);
+    	final IVirtualComponent webComp = ComponentCore.createComponent(webProject);
+ 	
+    	// add a cp dependency to the Utility
+    	ClasspathDependencyTestUtil.addCustomClasspathContainer(webJavaProject);
+    	
+    	return webComp;
+    }
    
   
     /**
      * 
      * @param verifyClasspathDependencies - true if you want to immediately verify that
      * the classpath dependencies were added.  Set to false if you want to verify this at
-     * a later time.  Such as thru a members call in export or publish.  
-     * Note: When set to true may fail a valid scenario due to JDT initialization issues.
+     * a later time (such as thru a members call in export or publish).  
      * @throws Exception
      */
     private void addDependencyAttribute(boolean verifyClasspathDependencies) throws Exception {
@@ -464,4 +605,43 @@
     	if (verifyClasspathDependencies)
     		ClasspathDependencyTestUtil.verifyClasspathDependencies(webComp, archiveNames);
     }
+    
+    /**
+     * 
+     * @param verifyClasspathDependencies - true if you want to immediately verify that
+     * the classpath dependencies were added.  Set to false if you want to verify this at
+     * a later time (such as thru a members call in export or publish)  
+     * @throws Exception
+     */
+    private void addEARLibDependencyAttribute(boolean verifyClasspathDependencies) throws Exception {
+
+    	final IProject web = ProjectUtil.getProject(WEB_PROJECT);
+    	final IJavaProject webJava = JavaCore.create(web);
+    	final IVirtualComponent webComp = ComponentCore.createComponent(web);
+    	
+    	final Set entryPaths = new HashSet();
+    	entryPaths.add(ClasspathDependencyTestUtil.CUSTOM_CLASSPATH_CONTAINER);
+    	// verify that "bin" and the custom cp container are potential entries
+    	List entries = ClasspathDependencyTestUtil.verifyPotentialClasspathEntries(webJava, entryPaths);
+    	// verify that no entries have the classpath attribute
+    	ClasspathDependencyTestUtil.verifyNoClasspathAttributes(webJava);
+    	// verify that there are no classpath dependencies
+    	ClasspathDependencyTestUtil.verifyNoClasspathDependencies(webComp);
+    	IClasspathEntry entry = (IClasspathEntry) entries.get(0);
+
+    	// add the dependency attribute to "bin" and the cp container    	
+    	for (Object o: entries) {
+    		UpdateClasspathAttributeUtil.addDependencyAttribute(null, web.getName(), (IClasspathEntry) o, new Path("../lib"));
+    	}
+    	// should no longer have potential entries
+    	ClasspathDependencyTestUtil.verifyNoPotentialClasspathEntries(webJava);
+    	// verify that "bin" and the cp container have the attribute
+    	ClasspathDependencyTestUtil.verifyClasspathAttributes(webJava, entryPaths);
+    	// verify that "bin" and the cp container are dependencies
+    	final Set archiveNames = new HashSet();
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST1_JAR);
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST2_JAR);
+    	if (verifyClasspathDependencies)
+    		ClasspathDependencyTestUtil.verifyClasspathDependencies(webComp, archiveNames);
+    }
 }
diff --git a/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyWebTests.java b/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyWebTests.java
index 9cca823..5688ec6 100644
--- a/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyWebTests.java
+++ b/tests/org.eclipse.jst.j2ee.tests/j2ee-tests/org/eclipse/jst/j2ee/classpath/tests/ClasspathDependencyWebTests.java
@@ -15,6 +15,9 @@
 import java.util.List;
 import java.util.Set;
 
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.CoreException;
@@ -35,12 +38,9 @@
 import org.eclipse.jst.j2ee.web.componentcore.util.WebArtifactEdit;
 import org.eclipse.wst.common.componentcore.ComponentCore;
 import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
-import org.eclipse.wst.server.core.util.ModuleFolder;
+import org.eclipse.wst.server.core.model.IModuleFolder;
 import org.eclipse.wst.server.core.model.IModuleResource;
 
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
 /**
  * Tests export and publish behavior for classpath component dependencies and web projects.
  */
@@ -60,6 +60,7 @@
         //suite.addTest(new ClasspathDependencyWebTests("testWebExportJEE5"));
         suite.addTest(new ClasspathDependencyWebTests("testWebPublishJ2EE"));
         suite.addTest(new ClasspathDependencyWebTests("testWebPublishJEE5"));
+        suite.addTest(new ClasspathDependencyWebTests("testWebContainerPublishJEE5"));
         return suite;
     }
     
@@ -83,7 +84,7 @@
     	verifyExportedWebInfLibs(webComp, archiveNames, false);
     	
     	// add the cp dependency attribute to the cp container in the util
-    	addDependencyAttribute();
+    	addDependencyAttribute(false);
     	
     	// verify that the exported WAR WEB-INF/lib does contain the cp container jars from the Utility
     	verifyExportedWebInfLibs(webComp, archiveNames, true);
@@ -148,6 +149,10 @@
         testWebPublish(true);
     }
     
+    public void testWebContainerPublishJEE5() throws Exception {
+        testWebContainerPublish(true);
+    }
+    
     private void testWebPublish(boolean JEE5) throws Exception {
 
     	// create the web and utility projects
@@ -160,14 +165,27 @@
     	verifyPublishedWebInfLibs(webComp, archiveNames, false);
     	
     	// add the cp dependency attribute to the cp container in the util
-    	addDependencyAttribute();
+    	addDependencyAttribute(true);
     	
     	// verify that the exported WAR WEB-INF/lib does contain the cp container jars from the Utility
     	verifyPublishedWebInfLibs(webComp, archiveNames, true);
     }
     
+    private void testWebContainerPublish(boolean JEE5) throws Exception {
+    	IVirtualComponent webComp = createWebProject(JEE5);
+    	
+    	final Set archiveNames = new HashSet();
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST1_JAR);
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST2_JAR);
+    	
+    	verifyPublishedWebInfContainer(webComp, archiveNames, false);
+    	
+    	addWebInfContainerDependencyAttribute(false);
+
+    	verifyPublishedWebInfContainer(webComp, archiveNames, true);
+    }
+    
     private void verifyPublishedWebInfLibs(final IVirtualComponent comp, final Set archiveNames, final boolean shouldHaveDependencies) throws Exception {
-    	// verify that the published WAR's WEB-INF/lib contains the cp container jars from the Utility
     	J2EEFlexProjDeployable deployable = new J2EEFlexProjDeployable(comp.getProject(), comp);
     	
 		try {
@@ -177,12 +195,12 @@
 			for (int i=0; i<members.length; i++) {
 				String name = members[i].getName();
 				if (name.equals("WEB-INF")) {
-					IModuleResource[] webInf = ((ModuleFolder)members[i]).members();
+					IModuleResource[] webInf = ((IModuleFolder)members[i]).members();
 					for (int j=0; j<webInf.length; j++) {
 						IModuleResource webResource = webInf[j];
 						assertTrue(webResource.getModuleRelativePath().toString().equals("WEB-INF"));
 						if (webResource.getName().equals("lib")) {
-							IModuleResource[] webresMembers = ((ModuleFolder)webResource).members();
+							IModuleResource[] webresMembers = ((IModuleFolder)webResource).members();
 							Iterator it = archiveNames.iterator();
 							while (it.hasNext()) {
 								String archiveName = (String) it.next();
@@ -200,10 +218,10 @@
 								}
 							}
 						} else if (webResource.getName().equals("classes")) {
-							IModuleResource[] webresMembers = ((ModuleFolder)webResource).members();
+							IModuleResource[] webresMembers = ((IModuleFolder)webResource).members();
 							for (j = 0; j < webresMembers.length; j++) {
 								if (webresMembers[j].getName().equals("nested")) {
-									IModuleResource[] nestedMembers = ((ModuleFolder)webresMembers[j]).members();
+									IModuleResource[] nestedMembers = ((IModuleFolder)webresMembers[j]).members();
 									assertTrue("Published WAR should have have nested folder without class folder dependency", shouldHaveDependencies);
 									boolean hasNestedTest = false;
 									if (nestedMembers.length == 1 && nestedMembers[0].getName().equals("test")) {
@@ -227,6 +245,49 @@
 		}    	
     }
     
+    private void verifyPublishedWebInfContainer(final IVirtualComponent comp, final Set archiveNames, final boolean shouldHaveDependencies) throws Exception {
+    	J2EEFlexProjDeployable deployable = new J2EEFlexProjDeployable(comp.getProject(), comp);
+    	
+		try {
+			IModuleResource[] members = deployable.members();
+			assertTrue(members.length==2);
+			
+			for (int i=0; i<members.length; i++) {
+				String name = members[i].getName();
+				if (name.equals("WEB-INF")) {
+					IModuleResource[] webInf = ((IModuleFolder)members[i]).members();
+					for (int j=0; j<webInf.length; j++) {
+						IModuleResource webResource = webInf[j];
+						assertTrue(webResource.getModuleRelativePath().toString().equals("WEB-INF"));
+						if (webResource.getName().equals("lib")) {
+							IModuleResource[] webresMembers = ((IModuleFolder)webResource).members();
+							Iterator it = archiveNames.iterator();
+							while (it.hasNext()) {
+								String archiveName = (String) it.next();
+								boolean hasArchive = false;
+								for (int k = 0; k < webresMembers.length; k++) {
+									String localName = webresMembers[k].getName();
+									if (localName.equals(archiveName)) {
+										hasArchive= true;
+									}
+								}
+								if (shouldHaveDependencies) {
+									assertTrue("Published WAR missing classpath dependency Jar " + archiveName, hasArchive);  					
+								} else {
+									assertFalse("Published WAR has unexpected classpath dependency Jar " + archiveName, hasArchive);
+								}
+							}
+						} 
+					}
+				} 
+			}
+
+		} catch (CoreException e) {
+			e.printStackTrace();
+			fail(e.getMessage());
+		}    	
+    }
+    
     private IVirtualComponent createProjects(boolean JEE5) throws Exception {
     	// create a Utility project
     	final IProject util = ProjectUtil.createUtilityProject(UTIL_PROJECT, null, true);
@@ -263,7 +324,30 @@
     	return webComp;
     }
     
-    private void addDependencyAttribute() throws Exception {
+    private IVirtualComponent createWebProject(boolean JEE5) throws Exception {
+    	// create a Web project
+    	int version = J2EEVersionConstants.SERVLET_2_5;
+    	if (!JEE5) {
+    		version = J2EEVersionConstants.SERVLET_2_4;
+    	}
+    	final IProject webProject = ProjectUtil.createWebProject(WEB_PROJECT, null, version, true);
+    	final IJavaProject webJavaProject = JavaCore.create(webProject);
+    	final IVirtualComponent webComp = ComponentCore.createComponent(webProject);
+ 	
+    	// add a cp dependency to the Utility
+    	ClasspathDependencyTestUtil.addCustomClasspathContainer(webJavaProject);
+    	
+    	return webComp;
+    }
+    
+    /**
+     * 
+     * @param verifyClasspathDependencies - true if you want to immediately verify that
+     * the classpath dependencies were added.  Set to false if you want to verify this at
+     * a later time (such as thru a members call in export or publish)  
+     * @throws Exception
+     */
+    private void addDependencyAttribute(boolean verifyClasspathDependencies) throws Exception {
     	final IProject util = ProjectUtil.getProject(UTIL_PROJECT);
     	final IJavaProject utilJava = JavaCore.create(util);
     	final IVirtualComponent utilComp = ComponentCore.createComponent(util);
@@ -308,4 +392,44 @@
     	archiveNames.add(fullWebBinPath.toString());
     	ClasspathDependencyTestUtil.verifyClasspathDependencies(webComp, archiveNames);
     }
+    
+    /**
+     * 
+     * @param verifyClasspathDependencies - true if you want to immediately verify that
+     * the classpath dependencies were added.  Set to false if you want to verify this at
+     * a later time (such as thru a members call in export or publish)  
+     * @throws Exception
+     */
+    private void addWebInfContainerDependencyAttribute(boolean verifyClasspathDependencies) throws Exception {
+
+    	final IProject web = ProjectUtil.getProject(WEB_PROJECT);
+    	final IJavaProject webJava = JavaCore.create(web);
+    	final IVirtualComponent webComp = ComponentCore.createComponent(web);
+    	
+    	final Set entryPaths = new HashSet();
+    	entryPaths.add(ClasspathDependencyTestUtil.CUSTOM_CLASSPATH_CONTAINER);
+    	// verify that "bin" and the custom cp container are potential entries
+    	List entries = ClasspathDependencyTestUtil.verifyPotentialClasspathEntries(webJava, entryPaths);
+    	// verify that no entries have the classpath attribute
+    	ClasspathDependencyTestUtil.verifyNoClasspathAttributes(webJava);
+    	// verify that there are no classpath dependencies
+    	ClasspathDependencyTestUtil.verifyNoClasspathDependencies(webComp);
+    	IClasspathEntry entry = (IClasspathEntry) entries.get(0);
+
+    	// add the dependency attribute to "bin" and the cp container    	
+    	for (Object o: entries) {
+    		UpdateClasspathAttributeUtil.addDependencyAttribute(null, web.getName(), (IClasspathEntry) o);
+    	}
+    	// should no longer have potential entries
+    	ClasspathDependencyTestUtil.verifyNoPotentialClasspathEntries(webJava);
+    	// verify that "bin" and the cp container have the attribute
+    	ClasspathDependencyTestUtil.verifyClasspathAttributes(webJava, entryPaths);
+    	// verify that "bin" and the cp container are dependencies
+    	final Set archiveNames = new HashSet();
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST1_JAR);
+    	archiveNames.add(ClasspathDependencyTestUtil.TEST2_JAR);
+    	if (verifyClasspathDependencies)
+    		ClasspathDependencyTestUtil.verifyClasspathDependencies(webComp, archiveNames);
+    }
+    
 }