/******************************************************************************* * 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 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.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); } } }