/******************************************************************************* | |
* Copyright (c) 2005, 2012 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License 2.0 | |
* which accompanies this distribution, and is available at | |
* https://www.eclipse.org/legal/epl-2.0/ | |
* | |
* SPDX-License-Identifier: EPL-2.0 | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.bpel.ui.commands; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Set; | |
import org.eclipse.bpel.model.EventHandler; | |
import org.eclipse.bpel.model.FaultHandler; | |
import org.eclipse.bpel.model.Flow; | |
import org.eclipse.bpel.model.Link; | |
import org.eclipse.bpel.model.PartnerLink; | |
import org.eclipse.bpel.model.Process; | |
import org.eclipse.bpel.model.partnerlinktype.PartnerLinkType; | |
import org.eclipse.bpel.model.util.BPELUtils; | |
import org.eclipse.bpel.ui.BPELEditor; | |
import org.eclipse.bpel.ui.Messages; | |
import org.eclipse.bpel.ui.adapters.IContainer; | |
import org.eclipse.bpel.ui.adapters.ILabeledElement; | |
import org.eclipse.bpel.ui.commands.util.AutoUndoCommand; | |
import org.eclipse.bpel.ui.util.BPELUtil; | |
import org.eclipse.bpel.ui.util.FlowLinkUtil; | |
import org.eclipse.bpel.ui.util.ModelHelper; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.jface.dialogs.MessageDialog; | |
import org.eclipse.osgi.util.NLS; | |
import org.eclipse.ui.PlatformUI; | |
import org.eclipse.wst.wsdl.Definition; | |
/** | |
* Deletes a model object from an IContainer, and removes any references to it | |
* from other model objects. | |
* | |
* This is more or less the opposite of InsertInContainerCommand. | |
* | |
* TODO: simplify this command now that it's an AutoUndoCommand! | |
*/ | |
public class DeleteChildCommand extends AutoUndoCommand { | |
private EObject fChild; | |
private EObject fParent; | |
IContainer fContainer; | |
Resource[] resourcesToModify = null; | |
CompoundCommand fDeleteLinksCmd; | |
CompoundCommand fDeletePLTsCmd; | |
public DeleteChildCommand(EObject child) { | |
super(new ArrayList(2)); | |
fParent = child.eContainer(); | |
if (fParent instanceof FaultHandler || fParent instanceof EventHandler) { | |
// If the child of the FH/EH is the *only* child, then we want to | |
// delete the | |
// entire FH/EH, since it has no meaningful attributes of its own. | |
IContainer<EObject> container = BPELUtil.adapt(fParent, | |
IContainer.class); | |
List<EObject> children = container.getChildren(fParent); | |
if (children.size() == 1 && children.contains(child)) { | |
// delete the FH instead | |
child = fParent; | |
fParent = child.eContainer(); | |
} | |
} | |
this.fChild = child; | |
if (fParent != null) { | |
addModelRoot(fParent); | |
} | |
fContainer = BPELUtil.adapt(fParent, IContainer.class); | |
String childType = null; | |
ILabeledElement labeledElement = BPELUtil.adapt(child, | |
ILabeledElement.class); | |
if (labeledElement != null) { | |
childType = labeledElement.getTypeLabel(child); | |
} | |
if (childType == null) { | |
childType = Messages.DeleteChildCommand_Item_1; | |
} | |
setLabel(NLS.bind(Messages.DeleteChildCommand_Delete_2, | |
(new Object[] { childType }))); | |
} | |
/** | |
* @see org.eclipse.bpel.ui.commands.util.AutoUndoCommand#canDoExecute() | |
*/ | |
@Override | |
public boolean canDoExecute() { | |
if (fChild == null || fParent == null || fContainer == null) { | |
return false; | |
} | |
return fContainer.canRemoveChild(fParent, fChild); | |
} | |
// TODO: this is a hack. | |
@Override | |
public Resource[] getResources() { | |
if (resourcesToModify == null) { | |
Process process = BPELUtils.getProcess(fParent); | |
if (process == null) | |
return EMPTY_RESOURCE_ARRAY; | |
BPELEditor bpelEditor = ModelHelper.getBPELEditor(process); | |
Set<Resource> resultSet = new HashSet<Resource>(); | |
resultSet.add(fParent.eResource()); | |
// Figure out which model objects are being deleted. | |
HashSet<Object> deletingSet = new HashSet<Object>(); | |
ModelHelper.addSubtreeToCollection(fChild, deletingSet); | |
// If we are deleting any PartnerLinks which reference PLTs in the | |
// Artifacts WSDL | |
// file, also delete the referenced PLTs. | |
Set<PartnerLinkType> partnerLinkTypes = null; | |
Definition artifactsDefinition = bpelEditor | |
.getArtifactsDefinition(); | |
for (Iterator it = deletingSet.iterator(); it.hasNext();) { | |
Object object = it.next(); | |
if (object instanceof PartnerLink) { | |
PartnerLinkType plt = ((PartnerLink) object) | |
.getPartnerLinkType(); | |
if ((plt != null) | |
&& (plt.getEnclosingDefinition() == artifactsDefinition)) { | |
if (partnerLinkTypes == null) | |
partnerLinkTypes = new HashSet<PartnerLinkType>(); | |
if (partnerLinkTypes.add(plt)) { | |
resultSet.add(plt.eResource()); | |
} | |
} | |
} | |
} | |
resourcesToModify = resultSet | |
.toArray(new Resource[resultSet.size()]); | |
} | |
return resourcesToModify; | |
} | |
/** | |
* @see org.eclipse.bpel.ui.commands.util.AutoUndoCommand#doExecute() | |
*/ | |
@Override | |
public void doExecute() { | |
if (!canExecute()) { | |
throw new IllegalStateException(); | |
} | |
Process process = BPELUtils.getProcess(fParent); | |
if (process == null) | |
return; | |
BPELEditor bpelEditor = ModelHelper.getBPELEditor(process); | |
EObject topModelObject = process; | |
// Multi-delete safety: if the child does not have a resource, assume it | |
// has | |
// already been deleted, and do nothing. | |
if (fChild.eResource() == null) { | |
return; | |
} | |
// Figure out which model objects are being deleted. | |
HashSet deletingSet = new HashSet(); | |
ModelHelper.addSubtreeToCollection(fChild, deletingSet); | |
// If we are deleting any PartnerLinks which reference PLTs in the | |
// Artifacts WSDL | |
// file, also delete the referenced PLTs. | |
Set<PartnerLinkType> partnerLinkTypes = null; | |
Definition artifactsDefinition = bpelEditor.getArtifactsDefinition(); | |
for (Iterator it = deletingSet.iterator(); it.hasNext();) { | |
Object object = it.next(); | |
if (object instanceof PartnerLink) { | |
PartnerLinkType plt = ((PartnerLink) object) | |
.getPartnerLinkType(); | |
if ((plt != null) | |
&& (plt.getEnclosingDefinition() == artifactsDefinition)) { | |
// We should ask the user if delete the partner link type | |
if (MessageDialog | |
.openQuestion( | |
PlatformUI.getWorkbench() | |
.getActiveWorkbenchWindow() | |
.getShell(), | |
Messages.DeletePartnerLinkTypeWarningDialogTitle, | |
NLS.bind(Messages.DeletePartnerLinkTypeWarningMessage, | |
(new Object[] {((PartnerLink) object).getName(), plt.getName() })))) { | |
if (partnerLinkTypes == null) | |
partnerLinkTypes = new HashSet<PartnerLinkType>(); | |
if (partnerLinkTypes.add(plt)) { | |
if (fDeletePLTsCmd == null) | |
fDeletePLTsCmd = new CompoundCommand(); | |
fDeletePLTsCmd | |
.add(new DeletePartnerLinkTypeCommand(plt)); | |
} | |
} | |
} | |
} | |
} | |
// TODO: Build the set of "all model objects" and subtract... | |
HashSet notDeletingSet = new HashSet(); | |
ModelHelper.addSubtreeToCollection(topModelObject, notDeletingSet); | |
notDeletingSet.removeAll(deletingSet); | |
// We also need to find any flow links which involve a deleted object | |
// and remove them. | |
// This is a hack, but it could be worse.. | |
// step 1: find all the flows which contain deleted objects | |
HashSet<Flow> flowSet = new HashSet<Flow>(); | |
for (Iterator<EObject> it = deletingSet.iterator(); it.hasNext();) { | |
Flow[] flws = FlowLinkUtil.getParentFlows(it.next()); | |
flowSet.addAll(Arrays.asList(flws)); | |
} | |
// step 2: if any of the flows is being deleted, we can ignore it | |
// this is safe because the source, dest and link itself are all | |
// children of the flow | |
flowSet.removeAll(deletingSet); | |
// step 3: check each link in each of the remaining flows to see if it | |
// involves a | |
// deleted object. Even if both source and target are being deleted, we | |
// should still | |
// delete the link, since it is a child of the Flow which is not being | |
// deleted. | |
fDeleteLinksCmd = new CompoundCommand(); | |
for (Iterator<Flow> flowIt = flowSet.iterator(); flowIt.hasNext();) { | |
Flow flow = flowIt.next(); | |
for (Iterator<Link> it = FlowLinkUtil.getFlowLinks(flow).iterator(); it | |
.hasNext();) { | |
Link link = it.next(); | |
if (deletingSet.contains(FlowLinkUtil.getLinkSource(link)) | |
|| deletingSet.contains(FlowLinkUtil | |
.getLinkTarget(link))) { | |
// NOTE: this is safe even if the link is scheduled for | |
// deletion by | |
// a GEF DeleteAction, see comment in DeleteLinkCommand. | |
DeleteLinkCommand child = new DeleteLinkCommand(link); | |
if (child.canExecute()) | |
fDeleteLinksCmd.add(child); | |
} | |
} | |
} | |
fDeleteLinksCmd.doExecute(); | |
if (fDeletePLTsCmd != null) { | |
fDeletePLTsCmd.doExecute(); | |
} | |
// finally, we can remove the child. | |
fContainer.removeChild(fParent, fChild); | |
// IMPORTANT: since the parent is a not-deleted object and the child | |
// will be | |
// a deleted object, this step must be done *after* the IContainer | |
// removal ;) | |
for (Iterator it = notDeletingSet.iterator(); it.hasNext();) { | |
BPELUtil.deleteNonContainmentRefs((EObject) it.next(), deletingSet); | |
} | |
} | |
} |