blob: e1026e7877531242fb1967e1b846cfa713c36b1c [file] [log] [blame]
/*******************************************************************************
* 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();
}
}
}
}