[121460] [modulecore] Behavior when multiple src dirs are mapped to component root
diff --git a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/IJavaEEDeploymentAssemblySectionBuilder.java b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/IJavaEEDeploymentAssemblySectionBuilder.java
new file mode 100644
index 0000000..0374c29
--- /dev/null
+++ b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/IJavaEEDeploymentAssemblySectionBuilder.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jst.j2ee.internal.ui;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.wst.common.componentcore.ui.propertypage.AddModuleDependenciesPropertiesPage.ComponentResourceProxy;
+
+public interface IJavaEEDeploymentAssemblySectionBuilder {
+
+	/**
+	 * Builds the section
+	 * @param parent - The composite to which this section will be added
+	 */
+	public void buildSection(Composite parent);
+
+	public void loadContents();
+
+	public boolean saveContents();
+	
+	public void directiveAdded(Object element);
+	
+	public void directiveRemoved(Object element);
+	
+	public IStatus validate(IStatus currentStatus);
+
+	public void componentResourceModified(ComponentResourceProxy originalResource, ComponentResourceProxy modifiedResource);
+	
+
+}
\ No newline at end of file
diff --git a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/J2EEModuleDependenciesPropertyPage.java b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/J2EEModuleDependenciesPropertyPage.java
index becd998..eda8a6b 100644
--- a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/J2EEModuleDependenciesPropertyPage.java
+++ b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/J2EEModuleDependenciesPropertyPage.java
@@ -1,5 +1,5 @@
 /******************************************************************************
- * Copyright (c) 2009 Red Hat and Others
+ * Copyright (c) 2009, 2011 Red Hat and Others
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -9,6 +9,7 @@
  *    Rob Stryker - initial implementation and ongoing maintenance
  *    Chuck Bridgham - additional support
  *    Konstantin Komissarchik - misc. UI cleanup
+ *    Roberto Sanchez - Add Advanced section
  ******************************************************************************/
 package org.eclipse.jst.j2ee.internal.ui;
 
@@ -37,6 +38,9 @@
 import org.eclipse.jst.j2ee.internal.plugin.J2EEUIPlugin;
 import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities;
 import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.wst.common.componentcore.internal.IModuleHandler;
 import org.eclipse.wst.common.componentcore.internal.impl.TaskModel;
@@ -52,10 +56,13 @@
 
 public class J2EEModuleDependenciesPropertyPage extends
 		AddModuleDependenciesPropertiesPage {
+	
+	private IJavaEEDeploymentAssemblySectionBuilder advancedHelper;
 
 	public J2EEModuleDependenciesPropertyPage(IProject project,
 			ModuleAssemblyRootPage page) {
 		super(project, page);
+		advancedHelper = getAdvancedSectionBuilder();
 	}
 	
 	public class ClasspathEntryProxy {
@@ -73,6 +80,15 @@
 		super.initialize();
 		resetClasspathEntries();
 	}
+	
+	@Override
+	protected void createTableComposite(Composite parent) {
+		Composite composite = new Composite(parent, SWT.NONE);
+		GridData gData = new GridData(GridData.FILL_BOTH);
+		composite.setLayoutData(gData);
+		fillTableComposite(composite);		
+		addAdvancedComposite(composite);
+	}
 
 	private void resetClasspathEntries() {
 		originalClasspathEntries.clear();
@@ -86,6 +102,8 @@
 	@Override
 	public void performDefaults() {
 		resetClasspathEntries();
+		if (advancedHelper != null)
+			advancedHelper.loadContents();
 		super.performDefaults();
 	}
 	
@@ -127,6 +145,8 @@
 		} else {
 			super.remove(selectedItem);
 		}
+		if (advancedHelper != null)
+			advancedHelper.directiveRemoved(selectedItem);
 	}
 	
 	@Override
@@ -197,8 +217,14 @@
 
 			@Override
 			public void modify(Object element, String property, Object value) {
-				if (property.equals(DEPLOY_PATH_PROPERTY)) {
+				ComponentResourceProxy originalResource = null;
+				ComponentResourceProxy modifiedResource = null;
+				if (property.equals(DEPLOY_PATH_PROPERTY)) {					
 					TreeItem item = (TreeItem) element;
+					if( item.getData() instanceof ComponentResourceProxy) {
+						modifiedResource = (ComponentResourceProxy)item.getData();
+						originalResource = new ComponentResourceProxy(modifiedResource.source, modifiedResource.runtimePath);						
+					}
 					if(item.getData() instanceof ClasspathEntryProxy){
 						TreeItem[] components = availableComponentsViewer.getTree().getItems();
 						int tableIndex = -1;
@@ -222,6 +248,8 @@
 					}
 				}
 				super.modify(element, property, value);
+				if (originalResource != null && advancedHelper != null)
+					advancedHelper.componentResourceModified(originalResource, modifiedResource);
 			}
 		};
 	}
@@ -306,6 +334,8 @@
 		{
 			super.handleAddDirective(wizard);
 		}
+		if (advancedHelper != null)
+			advancedHelper.directiveAdded(wizard.getTaskModel());
 	}
 	
 	@Override
@@ -318,8 +348,32 @@
 		ArrayList<ComponentResourceProxy> allMappings = new ArrayList<ComponentResourceProxy>();
 		allMappings.addAll(resourceMappings);
 		allMappings.addAll(hiddenMappings);
-		
-		return J2EEModuleDeploymentAssemblyVerifierHelper.verify(rootComponent, runtime, currentReferences, allMappings,resourceMappingsChanged, currentClasspathEntries);
+		IStatus status = J2EEModuleDeploymentAssemblyVerifierHelper.verify(rootComponent, runtime, currentReferences, allMappings,resourceMappingsChanged, currentClasspathEntries);
+		if (advancedHelper != null)
+			status = advancedHelper.validate(status); 
+		return status; 
+	}
+	
+	protected void addAdvancedComposite(Composite parent) {
+		if (advancedHelper != null) {
+			advancedHelper.buildSection(parent);
+			advancedHelper.loadContents();
+		}
+	}
+	
+	@Override
+	public boolean performOk() {
+		boolean result = super.performOk();
+		if (advancedHelper != null)
+			result = result & advancedHelper.saveContents();
+		return result;
+	}
+	
+	protected IJavaEEDeploymentAssemblySectionBuilder getAdvancedSectionBuilder(){
+		if (advancedHelper == null){
+			advancedHelper = new JavaEEDeploymentAssemblyAdvancedSectionBuilder(rootComponent, this);
+		}
+		return advancedHelper;		
 	}
 
 //	
diff --git a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/JavaEEDeploymentAssemblyAdvancedSectionBuilder.java b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/JavaEEDeploymentAssemblyAdvancedSectionBuilder.java
new file mode 100644
index 0000000..02f62c3
--- /dev/null
+++ b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/JavaEEDeploymentAssemblyAdvancedSectionBuilder.java
@@ -0,0 +1,437 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jst.j2ee.internal.ui;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jst.j2ee.componentcore.J2EEModuleVirtualComponent;
+import org.eclipse.jst.j2ee.internal.J2EEConstants;
+import org.eclipse.jst.j2ee.internal.plugin.J2EEUIPlugin;
+import org.eclipse.jst.j2ee.project.JavaEEProjectUtilities;
+import org.eclipse.jst.j2ee.project.facet.IJ2EEFacetConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.ui.forms.events.ExpansionAdapter;
+import org.eclipse.ui.forms.events.ExpansionEvent;
+import org.eclipse.ui.forms.widgets.ExpandableComposite;
+import org.eclipse.wst.common.componentcore.internal.ComponentResource;
+import org.eclipse.wst.common.componentcore.internal.StructureEdit;
+import org.eclipse.wst.common.componentcore.internal.WorkbenchComponent;
+import org.eclipse.wst.common.componentcore.internal.impl.TaskModel;
+import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
+import org.eclipse.wst.common.componentcore.resources.IVirtualFolder;
+import org.eclipse.wst.common.componentcore.ui.internal.propertypage.ResourceMappingFilterExtensionRegistry;
+import org.eclipse.wst.common.componentcore.ui.propertypage.AddModuleDependenciesPropertiesPage;
+import org.eclipse.wst.common.componentcore.ui.propertypage.AddModuleDependenciesPropertiesPage.ComponentResourceProxy;
+import org.eclipse.wst.common.componentcore.ui.propertypage.IReferenceWizardConstants;
+
+/**
+ * This is a helper class to build and handle the logic of the "Advanced" section 
+ * of the Deployment Assembly page that is common to all the Java EE modules (EAR
+ * project, Web project, etc.)
+ *  
+ */
+
+public class JavaEEDeploymentAssemblyAdvancedSectionBuilder implements IJavaEEDeploymentAssemblySectionBuilder, SelectionListener {
+	
+	private Label defaulDDFolderLabel;
+	private Combo rootSourceMappings;
+		
+	private IVirtualComponent rootComponent;
+	private AddModuleDependenciesPropertiesPage page;
+	private String currentSelectedDDFolder = null;
+	private List<String> resourceMappingsList = new ArrayList<String>();
+	boolean shouldDisplaySection;
+	
+	String folderToLook;
+	String fileToLook;
+	String projectType;
+	
+	
+	public JavaEEDeploymentAssemblyAdvancedSectionBuilder(IVirtualComponent component, AddModuleDependenciesPropertiesPage page){
+		rootComponent = component;
+		this.page = page;
+		shouldDisplaySection = !JavaEEProjectUtilities.isUtilityProject(rootComponent.getProject());
+		IVirtualFolder rootFolder = rootComponent.getRootFolder();
+		IPath defaultDDFolder = J2EEModuleVirtualComponent.getDefaultDeploymentDescriptorFolder(rootFolder);
+		shouldDisplaySection &= (defaultDDFolder == null);
+		projectType = JavaEEProjectUtilities.getJ2EEProjectType(component.getProject());
+		if (projectType.equals(IJ2EEFacetConstants.APPLICATION_CLIENT))	{
+			folderToLook = J2EEConstants.META_INF;
+			fileToLook = J2EEConstants.APP_CLIENT_DD_URI;
+		}
+		else if (projectType.equals(IJ2EEFacetConstants.JCA)) {
+			folderToLook = J2EEConstants.META_INF;
+			fileToLook = J2EEConstants.RAR_DD_URI;
+		}
+		else if	(projectType.equals(IJ2EEFacetConstants.EJB)){
+			folderToLook = J2EEConstants.META_INF;
+			fileToLook = J2EEConstants.EJBJAR_DD_URI;
+		}
+		else if (projectType.equals(IJ2EEFacetConstants.DYNAMIC_WEB)) {
+			folderToLook = J2EEConstants.WEB_INF;
+			fileToLook = J2EEConstants.WEBAPP_DD_URI;
+		}
+		else if (projectType.equals(IJ2EEFacetConstants.ENTERPRISE_APPLICATION)) {
+			folderToLook = J2EEConstants.META_INF;
+			fileToLook = J2EEConstants.APPLICATION_DD_URI;
+		}	
+		else if (projectType.equals(IJ2EEFacetConstants.WEBFRAGMENT)) {
+			folderToLook = J2EEConstants.META_INF;
+			fileToLook = J2EEConstants.WEBFRAGMENT_DD_URI;
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jst.j2ee.internal.ui.IJavaEEDeploymentAssemblySectionBuilder#buildSection(org.eclipse.swt.widgets.Composite)
+	 */
+	public void buildSection(Composite parent){
+		if (shouldDisplaySection()) { 
+			Composite advancedSectionComposite = createAdvancedSection(parent);		
+			addDefaultDeploymentDescriptorFolderFields(advancedSectionComposite);
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jst.j2ee.internal.ui.IJavaEEDeploymentAssemblySectionBuilder#loadContents()
+	 */
+	public void loadContents(){
+		if (shouldDisplaySection()){
+			loadDefaultDeploymentDescriptorFolderContents();
+		}
+	}
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.jst.j2ee.internal.ui.IJavaEEDeploymentAssemblySectionBuilder#saveContents()
+	 */
+	public boolean saveContents(){		
+		boolean success = true;
+		if (shouldDisplaySection()){
+			success = saveDefaultDeploymentDescriptorFolderContents();
+			loadContents();
+		}
+		return success;
+	}
+	
+	
+	private void loadDefaultDeploymentDescriptorFolderContents(){
+		resourceMappingsList.clear();
+		// First, retrieve all the mappings to root. Assume there are no duplicated mappings.
+		IPath[] allRootMappings = findAllRootMappings();		
+		// Now, see if any of that is tagged as default root mapping
+		IVirtualFolder rootFolder = rootComponent.getRootFolder();
+		IPath defaultDDFolder = J2EEModuleVirtualComponent.getDefaultDeploymentDescriptorFolder(rootFolder);
+		
+		currentSelectedDDFolder = defaultDDFolder == null?null:defaultDDFolder.toString();
+				
+		for (IPath mapping:allRootMappings){
+			resourceMappingsList.add(mapping.toString());
+		}
+		
+		updateSourceMappingsCombo(currentSelectedDDFolder, resourceMappingsList);
+	}
+	
+	
+	private List<String> filterMappings(List <String> mappings){
+		Set<String> mappingWithDD = new HashSet<String>();
+		Set<String> mappingWithFolder = new HashSet<String>();
+		
+		IProject project = this.rootComponent.getProject();
+		for (String mapping :mappings){
+			if (fileToLook != null && !fileToLook.equals("")){ //$NON-NLS-1$
+				IFile ddFile = project.getFile(new Path(mapping).addTrailingSeparator() + fileToLook);
+				if (ddFile != null && ddFile.exists()){
+					mappingWithDD.add(mapping);
+					return new ArrayList<String>(mappingWithDD);
+				}
+			}
+			if (folderToLook != null && !folderToLook.equals("")){ //$NON-NLS-1$
+				IFolder ddFolder = project.getFolder(new Path(mapping).addTrailingSeparator() + folderToLook);
+				if (ddFolder != null && ddFolder.exists()){
+					mappingWithFolder.add(mapping);
+				}
+			}
+		}
+		return  new ArrayList<String>(mappingWithFolder);
+	}
+	
+	private void updateSourceMappingsCombo(String selectedDDFolder, List<String> resourceMappings) {
+		
+		List<String> filteredMappings = filterMappings(resourceMappings);
+		
+		ArrayList<String> tmpList = new ArrayList<String>(filteredMappings);
+		if (selectedDDFolder == null){
+			tmpList.add(0, Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER);
+		}
+		rootSourceMappings.setItems(tmpList.toArray(new String[]{}));
+		if (selectedDDFolder == null){
+			//No tagged source folder, so select "None"
+			rootSourceMappings.select(tmpList.indexOf(Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER));
+		}
+		else {
+			rootSourceMappings.select(tmpList.indexOf(selectedDDFolder.toString()));
+		}					
+	}
+
+	private boolean saveDefaultDeploymentDescriptorFolderContents(){		
+		if (currentSelectedDDFolder != null){
+			IVirtualFolder rootFolder = rootComponent.getRootFolder();
+			J2EEModuleVirtualComponent.setDefaultDeploymentDescriptorFolder(rootFolder, new Path(currentSelectedDDFolder), null);
+		}
+		return true;
+	}
+	
+	private IPath[] findAllRootMappings(){
+		
+		StructureEdit structureEdit = null;
+		try {
+			structureEdit = StructureEdit.getStructureEditForRead(rootComponent.getProject());
+			WorkbenchComponent component = structureEdit.getComponent();
+			Object[] arr = component.getResources().toArray();
+			Set <IPath> result = new LinkedHashSet<IPath>();
+			for( int i = 0; i < arr.length; i++ ){
+				ComponentResource resource = (ComponentResource)arr[i];
+				if (resource.getRuntimePath().equals(IVirtualComponent.ROOT) && !ResourceMappingFilterExtensionRegistry.shouldFilter(resource.getSourcePath())){
+					result.add(((ComponentResource)arr[i]).getSourcePath());
+				}
+			}
+			return result.toArray(new IPath[]{});
+		} catch (NullPointerException e) {
+			J2EEUIPlugin.logError(e);
+		} finally {
+			if(structureEdit != null)
+				structureEdit.dispose();
+		}
+		return new IPath[]{};
+	}
+	
+	protected boolean shouldDisplaySection(){
+		return shouldDisplaySection;
+	}
+		
+	/*
+	 * Creates the Advanced section. Returns the composite to which all the other 
+	 * widgets should be added.
+	 */
+	private Composite createAdvancedSection(Composite parent){		
+		
+		// Build the expandable composite
+		ExpandableComposite excomposite = new ExpandableComposite(parent, SWT.NONE, ExpandableComposite.TWISTIE
+		| ExpandableComposite.CLIENT_INDENT | ExpandableComposite.COMPACT);
+		excomposite.setText(Messages.J2EEModuleDependenciesPropertyPage_ADVANCED);
+		excomposite.setExpanded(false);
+		excomposite.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT));
+		excomposite.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, 1, 1));
+		excomposite.addExpansionListener(new ExpansionAdapter() {
+			@Override
+			public void expansionStateChanged(ExpansionEvent e) {
+				expandedStateChanged((ExpandableComposite) e.getSource());
+			}
+		});
+
+		// Build the composite has the contents of the expandable widget
+		Composite innerComposite = new Composite(excomposite, SWT.NONE);
+		excomposite.setClient(innerComposite);
+		GridLayout gl = new GridLayout(2, false);
+		gl.marginHeight = 0;
+		gl.marginWidth = 0;
+		innerComposite.setLayout(gl); 
+		return innerComposite;		
+	}
+	
+	private void addDefaultDeploymentDescriptorFolderFields(Composite parent) {
+		defaulDDFolderLabel = new Label(parent, SWT.NONE);
+		defaulDDFolderLabel.setText(Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_DDFOLDER);
+		rootSourceMappings = new Combo(parent, SWT.READ_ONLY);
+		rootSourceMappings.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		rootSourceMappings.addSelectionListener(this);
+	}
+	
+	
+	private final void expandedStateChanged(ExpandableComposite expandable) {
+		// Get the scrolled composite of the deployment assembly page, and the child
+		// composite of this scrolled composite that contains the expandable composite 
+		Composite[] composites = getCompositesToResize(expandable);
+		ScrolledComposite parentScrolledComposite = (ScrolledComposite)composites[0];
+		Composite childComposite = composites[1];
+		if (parentScrolledComposite != null && childComposite != null) {
+			parentScrolledComposite.layout(true, true);
+			// Resize the scrolled composite so the scroll bars are shown if necessary
+			parentScrolledComposite.setMinSize(childComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT, true));
+			
+		}
+	}
+	
+	/*
+	 * Returns an array of composites used to resize the deployment assembly page
+	 * when the advanced section is expanded.
+	 * The first element is the scrolled composite (instance of ScrolledComposite) of the 
+	 * deployment assembly page
+	 * The second element is the composite with the contents of the deployment assembly page
+	 */
+	private Composite[] getCompositesToResize(Control control) {
+		Control parent = control.getParent();
+		Control previousParent = null;
+		Composite[] result = new Composite[2];
+		while (!(parent instanceof ScrolledComposite) && parent != null) {
+			previousParent = parent;
+			parent = parent.getParent();
+		}
+		if (parent instanceof ScrolledComposite) {
+			result[0] = (ScrolledComposite)parent;
+		}
+		if (previousParent instanceof Composite) {
+			result[1] = (Composite)previousParent;
+		}
+		return result;
+	}
+
+	public void directiveAdded(Object element) {
+		if (shouldDisplaySection()){
+			if (!(element instanceof TaskModel))
+				return;
+			TaskModel model = (TaskModel)element;
+			final Object folderMapping = model.getObject(IReferenceWizardConstants.FOLDER_MAPPING);		
+			if( folderMapping != null && folderMapping instanceof ComponentResourceProxy){
+				ComponentResourceProxy proxy = (ComponentResourceProxy)folderMapping;
+				//if ((proxy.runtimePath.equals(IVirtualComponent.ROOT) && !resourceMappingsList.contains(proxy.source.toString()))){
+				if ((proxy.runtimePath.equals(IVirtualComponent.ROOT))){
+					resourceMappingsList.add(proxy.source.toString());
+					updateSourceMappingsCombo(currentSelectedDDFolder, resourceMappingsList);
+				}
+			}
+		}		
+	}
+
+	public void directiveRemoved(Object element) {
+		if (shouldDisplaySection()){
+			if( element instanceof ComponentResourceProxy){
+				ComponentResourceProxy proxy = (ComponentResourceProxy)element;
+				if (proxy.runtimePath.equals(IVirtualComponent.ROOT)){
+					String proxySource = proxy.source.toString();
+					if (resourceMappingsList.contains(proxySource)){
+						resourceMappingsList.remove(proxySource);
+						if (proxySource.equals(currentSelectedDDFolder)){
+							currentSelectedDDFolder = null;
+						}
+						updateSourceMappingsCombo(currentSelectedDDFolder, resourceMappingsList);
+					}					
+				}			
+			}
+		}
+	}
+
+	public void widgetDefaultSelected(SelectionEvent event) {
+		// Intentionally left blank
+		
+	}
+
+	public void widgetSelected(SelectionEvent event) {
+		if (event.getSource() == rootSourceMappings){
+			String tmp = rootSourceMappings.getText();
+			if (tmp != null){
+				if (tmp.equals(Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER) && currentSelectedDDFolder == null){
+					// Do nothing, because the value did not change.
+					return;
+				}
+				if (tmp.equals(Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER)){
+					// This means the user selected None, but there was already a value selected (this should not happen)
+					J2EEUIPlugin.logWarning("Unexpected condition when validating deployment descriptor folder"); //$NON-NLS-1$
+					return;
+				}
+				// We now the user selected something different from None, so remove this item so it cannot be selected again
+				if (rootSourceMappings.indexOf(Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER) != -1)
+					rootSourceMappings.remove(Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER);
+				// Only refresh if changing from None to a folder
+				boolean shouldRefresh = (currentSelectedDDFolder == null);
+				if (!tmp.equals(currentSelectedDDFolder)){  
+					currentSelectedDDFolder = tmp;
+					if (shouldRefresh)
+						page.refresh();
+				}
+			}
+		}
+				
+	}
+
+	public IStatus validate(IStatus currentStatus) {	
+		IStatus status = currentStatus!=null?currentStatus:Status.OK_STATUS;
+		if (shouldDisplaySection()){
+			if (currentSelectedDDFolder == null && resourceMappingsList.size()>1){
+				// Only show the warning if none of the root mappings is selected and there are more than 1 root mapping				
+				int severity = Status.WARNING;
+				status = appendStatusMessage(status, Messages.J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDERWARNING, severity);
+			}
+		}
+		return status;
+	}
+	private IStatus appendStatusMessage(IStatus existingStatus, String message, int severity) {
+        MultiStatus multiStatus;
+        IStatus newStatus = new Status(severity, J2EEUIPlugin.PLUGIN_ID, message);
+		int newSeverity = severity;
+		if(existingStatus.getSeverity() > severity)
+			newSeverity = existingStatus.getSeverity();
+        if(existingStatus instanceof MultiStatus){
+            multiStatus = (MultiStatus)existingStatus;
+            multiStatus.merge(newStatus);
+        } else {
+        	if(!existingStatus.isMultiStatus() && existingStatus.isOK()) {
+        		return newStatus;
+        	}
+            IStatus [] children = new IStatus [] {existingStatus, newStatus};
+            multiStatus = new MultiStatus(J2EEUIPlugin.PLUGIN_ID, newSeverity, children, null, null);
+        }
+        return multiStatus;
+    }
+
+	public void componentResourceModified(ComponentResourceProxy originalResource, ComponentResourceProxy modifiedResource) {
+		if (shouldDisplaySection()){
+			// We are interested only in two cases:
+			// 1. When the deploy path changes from / to any other thing...
+			if (originalResource.runtimePath.isRoot() && !modifiedResource.runtimePath.isRoot()){
+				resourceMappingsList.remove(originalResource.source.toString());
+				if (originalResource.source.toString().equals(currentSelectedDDFolder)){
+					currentSelectedDDFolder = null; 
+				}
+				updateSourceMappingsCombo(currentSelectedDDFolder, resourceMappingsList);
+				page.refresh();
+			}
+			// 2. When the deploy path changes from any thing to /
+			else if (!originalResource.runtimePath.isRoot() && modifiedResource.runtimePath.isRoot()){
+				resourceMappingsList.add(originalResource.source.toString());
+				updateSourceMappingsCombo(currentSelectedDDFolder, resourceMappingsList);
+				page.refresh();		
+			}
+		}	
+	}
+}
diff --git a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/Messages.java b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/Messages.java
index 649a90c..9e1b485 100644
--- a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/Messages.java
+++ b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/Messages.java
@@ -17,6 +17,10 @@
 	public static String J2EEModuleDependenciesPropertyPage_4;
 	public static String J2EEModuleDependenciesPropertyPage_5;
 	public static String J2EEModuleDependenciesPropertyPage_6;
+	public static String J2EEModuleDependenciesPropertyPage_ADVANCED;
+	public static String J2EEModuleDependenciesPropertyPage_ADVANCED_DDFOLDER;
+	public static String J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER;
+	public static String J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDERWARNING;
 
 	static {
 		// initialize resource bundle
diff --git a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/messages.properties b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/messages.properties
index 8b11dc6..87c77fd 100644
--- a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/messages.properties
+++ b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/messages.properties
@@ -11,4 +11,8 @@
 J2EEModuleDependenciesPropertyPage_4=Assemble packaging structure for this Application Client project
 J2EEModuleDependenciesPropertyPage_5=Assemble packaging structure for this Connector project
 J2EEModuleDependenciesPropertyPage_6=Derived References
+J2EEModuleDependenciesPropertyPage_ADVANCED=Advanced
+J2EEModuleDependenciesPropertyPage_ADVANCED_DDFOLDER=Folder for deplo&yment descriptor:
+J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDER=(None)
+J2EEModuleDependenciesPropertyPage_ADVANCED_NODEFAULTDDFOLDERWARNING=A deployment descriptor folder should be selected. See the Advanced section.
 
diff --git a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/preferences/EarModuleDependenciesPropertyPage.java b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/preferences/EarModuleDependenciesPropertyPage.java
index 77ed871..f08563f 100644
--- a/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/preferences/EarModuleDependenciesPropertyPage.java
+++ b/plugins/org.eclipse.jst.j2ee.ui/j2ee_ui/org/eclipse/jst/j2ee/internal/ui/preferences/EarModuleDependenciesPropertyPage.java
@@ -1,5 +1,5 @@
 /******************************************************************************
- * Copyright (c) 2009 Red Hat, IBM
+ * Copyright (c) 2009, 2011 Red Hat, IBM
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -8,6 +8,7 @@
  * Contributors:
  *    Rob Stryker - initial implementation and ongoing maintenance
  *    Chuck Bridgham - additional support
+ *    Roberto Sanchez - Add Advanced section
  ******************************************************************************/
 package org.eclipse.jst.j2ee.internal.ui.preferences;
 
@@ -34,8 +35,10 @@
 import org.eclipse.jst.j2ee.internal.plugin.J2EEUIMessages;
 import org.eclipse.jst.j2ee.internal.plugin.J2EEUIPlugin;
 import org.eclipse.jst.j2ee.internal.project.J2EEProjectUtilities;
+import org.eclipse.jst.j2ee.internal.ui.IJavaEEDeploymentAssemblySectionBuilder;
 import org.eclipse.jst.j2ee.internal.ui.J2EEModuleDependenciesPropertyPage.ClasspathEntryProxy;
 import org.eclipse.jst.j2ee.internal.ui.JavaEEComponentDependencyContentProvider;
+import org.eclipse.jst.j2ee.internal.ui.JavaEEDeploymentAssemblyAdvancedSectionBuilder;
 import org.eclipse.jst.j2ee.model.IEARModelProvider;
 import org.eclipse.jst.j2ee.model.ModelProviderManager;
 import org.eclipse.jst.j2ee.project.EarUtilities;
@@ -53,6 +56,7 @@
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeItem;
 import org.eclipse.wst.common.componentcore.internal.IModuleHandler;
 import org.eclipse.wst.common.componentcore.internal.impl.TaskModel;
 import org.eclipse.wst.common.componentcore.internal.resources.VirtualArchiveComponent;
@@ -79,10 +83,12 @@
 	private ControlDecoration libDirTextErrorDecoration = null;
 	private static String earDefaultLirDir = new Path(J2EEConstants.EAR_DEFAULT_LIB_DIR).makeRelative().toString();
 	boolean previousLibDirIsValid = true;
+	private IJavaEEDeploymentAssemblySectionBuilder advancedHelper;
 	
 	public EarModuleDependenciesPropertyPage(IProject project,
 			ModuleAssemblyRootPage page) {
 		super(project, page);
+		advancedHelper = getAdvancedSectionBuilder();
 	}
 	
 	@Override
@@ -93,6 +99,7 @@
 		fillTableComposite(composite);
 		if(JavaEEProjectUtilities.isJEEComponent(rootComponent, JavaEEProjectUtilities.DD_VERSION) && JavaEEProjectUtilities.isJEEComponent(rootComponent, JavaEEProjectUtilities.FACET_VERSION))
 			addLibDirComposite(composite);
+		addAdvancedComposite(composite);
 	}
 
 	private String loadLibDirString() {
@@ -123,6 +130,7 @@
 				public void modifyText(ModifyEvent e) {
 					libDirTextModified();
 				} });
+			new Label(parent, SWT.NONE); //Place holder to fill the second column 
 		}
 	}
 	
@@ -256,6 +264,8 @@
 		boolean result = super.performOk();
 		if(JavaEEProjectUtilities.isJEEComponent(rootComponent, JavaEEProjectUtilities.DD_VERSION) && JavaEEProjectUtilities.isJEEComponent(rootComponent, JavaEEProjectUtilities.FACET_VERSION) && libDir != null)
 			updateLibDir();
+		if (advancedHelper != null)
+			result = result & advancedHelper.saveContents();
 		return result;
 	}
 	
@@ -325,6 +335,12 @@
 	}
 	
 	@Override
+	protected void remove(Object selectedItem) {
+		super.remove(selectedItem);
+		advancedHelper.directiveRemoved(selectedItem);
+	}
+	
+	@Override
 	public IStatus validate() {
 		IStatus status = super.validate();
 		validatelibDirText();
@@ -334,6 +350,7 @@
 				severity = Status.WARNING;	
 			status = appendStatusMessage(status, libDirTextErrorDecoration.getDescriptionText(), severity);
 		}
+		status = advancedHelper.validate(status);
 		return status;
 	}
 	
@@ -342,6 +359,8 @@
 		libDir = loadLibDirString();
 		if(libDir != null)
 			libDirText.setText(libDir);
+		if (advancedHelper != null)
+			advancedHelper.loadContents();
 		super.performDefaults();
 	}
 	
@@ -398,5 +417,41 @@
 				}
 			}
 		}
+		advancedHelper.directiveAdded(wizard.getTaskModel());
+	}
+	
+	protected void addAdvancedComposite(Composite parent) {
+		if (advancedHelper != null) {
+			advancedHelper.buildSection(parent);
+			advancedHelper.loadContents();
+		}
+	}
+	
+	protected IJavaEEDeploymentAssemblySectionBuilder getAdvancedSectionBuilder(){
+		if (advancedHelper == null){
+			advancedHelper = new JavaEEDeploymentAssemblyAdvancedSectionBuilder(rootComponent, this);
+		}
+		return advancedHelper;		
+	}
+	
+	@Override
+	protected RuntimePathCellModifier getRuntimePathCellModifier() {
+		return new AddModuleDependenciesPropertiesPage.RuntimePathCellModifier(){
+			@Override
+			public void modify(Object element, String property, Object value) {
+				ComponentResourceProxy originalResource = null;
+				ComponentResourceProxy modifiedResource = null;
+				if (property.equals(DEPLOY_PATH_PROPERTY)) {					
+					TreeItem item = (TreeItem) element;
+					if( item.getData() instanceof ComponentResourceProxy) {
+						modifiedResource = (ComponentResourceProxy)item.getData();
+						originalResource = new ComponentResourceProxy(modifiedResource.source, modifiedResource.runtimePath);						
+					}
+				}
+				super.modify(element, property, value);
+				if (originalResource != null && advancedHelper != null)
+					advancedHelper.componentResourceModified(originalResource, modifiedResource);
+			}	
+		};
 	}
 }