/******************************************************************************* * 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); } } 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); } } } if (!mappingWithDD.isEmpty()){ // return only the mappings that contain a DD file. return new ArrayList<String>(mappingWithDD); } 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(); } } } }