/******************************************************************************* | |
* 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.util; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Iterator; | |
import java.util.List; | |
import org.eclipse.bpel.model.Activity; | |
import org.eclipse.bpel.model.BPELFactory; | |
import org.eclipse.bpel.model.Flow; | |
import org.eclipse.bpel.model.Link; | |
import org.eclipse.bpel.model.Source; | |
import org.eclipse.bpel.model.Target; | |
import org.eclipse.emf.ecore.EObject; | |
/** | |
* Helpers for dealing with Links in a Flow. | |
* | |
* TODO: do all these helpers work OK if the Sources or Targets list is empty?? | |
*/ | |
public class FlowLinkUtil { | |
/** | |
* Walks up the parent chain of the source and target activities to find the innermost flow | |
* which contains both. Returns null if source and target have no common flow. | |
*/ | |
public static Flow getCommonFlow(Activity source, Activity target) { | |
if (source == null || target == null) return null; | |
Flow[] sourceParents = getParentFlows(source); | |
Flow[] targetParents = getParentFlows(target); | |
if (sourceParents == null || targetParents == null) return null; | |
int sIdx = sourceParents.length - 1; | |
int tIdx = targetParents.length - 1; | |
Flow commonFlow = null; | |
while (sIdx >= 0 && tIdx >= 0) { | |
if (sourceParents[sIdx] == targetParents[tIdx]) { | |
commonFlow = sourceParents[sIdx]; | |
} else { | |
break; | |
} | |
sIdx--; tIdx--; | |
} | |
return commonFlow; | |
} | |
/** | |
* Returns true if the given object is enclosed in a flow, or false otherwise. | |
*/ | |
public static boolean hasParentFlow(EObject object) { | |
for (object = object.eContainer(); object != null; object = object.eContainer()) { | |
if (object instanceof Flow) return true; | |
} | |
return false; | |
} | |
/** | |
* Walks up the parent chain of the given object and returns all the parents which are | |
* Flows, from the innermost (i.e. closest ancestor) to outermost (oldest ancestor). | |
* | |
* The returned array will have non-zero length if and only if hasParentFlow(object) is true. | |
*/ | |
public static Flow[] getParentFlows(EObject object) { | |
List list = new ArrayList(); | |
getParentFlows(object.eContainer(), list); | |
return (Flow[])list.toArray(new Flow[list.size()]); | |
} | |
protected static void getParentFlows(EObject object, List list) { | |
if (object == null) return; | |
if (object instanceof Process) return; | |
if (object instanceof Flow) list.add(object); | |
getParentFlows(object.eContainer(), list); | |
} | |
/** | |
* Returns a list of links. | |
* Callers should NOT MODIFY this list as it may not be the real list! | |
*/ | |
public static List getFlowLinks(Flow flow) { | |
if (flow.getLinks() == null) { | |
return Collections.EMPTY_LIST; | |
} | |
return Collections.unmodifiableList(flow.getLinks().getChildren()); | |
} | |
public static void addFlowLink(Flow flow, Link link) { | |
if (flow.getLinks() == null) { | |
flow.setLinks(BPELFactory.eINSTANCE.createLinks()); | |
} | |
flow.getLinks().getChildren().add(link); | |
} | |
public static void removeFlowLink(Flow flow, Link link) { | |
if (flow.getLinks() != null) { | |
flow.getLinks().getChildren().remove(link); | |
if (flow.getLinks().getChildren().isEmpty()) { | |
flow.setLinks(null); | |
} | |
} | |
} | |
public static void removeActivitySource(Source source) { | |
Activity activity = source.getActivity(); | |
if (activity != null && activity.getSources() != null) { | |
activity.getSources().getChildren().remove(source); | |
if (activity.getSources().getChildren().isEmpty()) { | |
activity.setSources(null); | |
} | |
} | |
} | |
public static void removeActivityTarget(Target target) { | |
Activity activity = target.getActivity(); | |
if (activity != null && activity.getTargets() != null) { | |
activity.getTargets().getChildren().remove(target); | |
if (activity.getTargets().getChildren().isEmpty()) { | |
activity.setTargets(null); | |
} | |
} | |
} | |
/** | |
* Returns the source of a Link, or null if it has none. | |
*/ | |
public static Activity getLinkSource(Link link) { | |
if (link.getSources().isEmpty()) return null; | |
return ((link.getSources().get(0))).getActivity(); | |
} | |
/** | |
* Returns the target of a Link, or null if it has none. | |
*/ | |
public static Activity getLinkTarget(Link link) { | |
if (link.getTargets().isEmpty()) return null; | |
return ((link.getTargets().get(0))).getActivity(); | |
} | |
/** | |
* Sets the source of a Link. | |
*/ | |
public static void setLinkSource(Link link, Activity activity) { | |
if (link.getSources().isEmpty()) { | |
if (activity != null) { | |
// Create new Source. | |
Source source = BPELFactory.eINSTANCE.createSource(); | |
link.getSources().add(source); | |
source.setActivity(activity); | |
} | |
} else { | |
Source source = (link.getSources().get(0)); | |
Activity oldActivity = source.getActivity(); | |
if (activity != null) { | |
// Re-target existing Source. TODO: is this safe? | |
source.setActivity(activity); | |
} else { | |
link.getSources().remove(source); | |
} | |
// In either case, the previous activity to which the | |
// source was attached may now have an empty sources element. | |
// If so, remove it now. | |
if (oldActivity != null) { | |
if (oldActivity.getSources() != null && oldActivity.getSources().getChildren().isEmpty()) { | |
oldActivity.setSources(null); | |
} | |
} | |
} | |
} | |
/** | |
* Sets the target of a Link. | |
*/ | |
public static void setLinkTarget(Link link, Activity activity) { | |
if (link.getTargets().isEmpty()) { | |
if (activity != null) { | |
// Create new Target. | |
Target target = BPELFactory.eINSTANCE.createTarget(); | |
link.getTargets().add(target); | |
target.setActivity(activity); | |
} | |
} else { | |
Target target = (link.getTargets().get(0)); | |
Activity oldActivity = target.getActivity(); | |
if (activity != null) { | |
// Re-target existing Target. TODO: is this safe? | |
target.setActivity(activity); | |
} else { | |
// Remove existing Target. | |
link.getTargets().remove(target); | |
} | |
// In either case, the previous activity to which the | |
// target was attached may now have an empty targets element. | |
// If so, remove it now. | |
if (oldActivity != null) { | |
if (oldActivity.getTargets() != null && oldActivity.getTargets().getChildren().isEmpty()) { | |
oldActivity.setTargets(null); | |
} | |
} | |
} | |
} | |
/** | |
* If the from Activity is a source or target in a Link it is | |
* replaced by the to Activity. Nothing happens otherwise. | |
* | |
* TODO: this was only used by some generic fault-handler stuff in ActivityAdapter. | |
* Consider removing this in the future, if we don't need that stuff anymore! | |
*/ | |
public static void replaceLinkSourceAndTarget(Activity from, Activity to) { | |
Flow[] flows = getParentFlows(from); | |
if (flows != null && flows.length > 0) { | |
Flow flow = flows[0]; | |
List links = getFlowLinks(flow); | |
for (Iterator iter = links.iterator(); iter.hasNext();) { | |
Link link = (Link) iter.next(); | |
Activity temp = getLinkSource(link); | |
if (temp != null && temp == from) { | |
setLinkSource(link, to); | |
} else { | |
temp = getLinkTarget(link); | |
if (temp != null && temp == from) { | |
setLinkTarget(link, to); | |
} | |
} | |
} | |
} | |
} | |
// /** | |
// * Returns the EditPart which should act as the source for a given Link object. | |
// * (this depends on the collapsed/expanded state..its basically the source Activity | |
// * itself, or its innermost enclosing container, which is actually visible) | |
// */ | |
// public static EditPart getActingSourceEditPart(EditPartViewer viewer, Link link) { | |
// EObject modelObject = getLinkSource(link); | |
// while (modelObject != null) { | |
// EditPart editPart = (EditPart)viewer.getEditPartRegistry().get(modelObject); | |
// if (editPart != null) return editPart; | |
// modelObject = BPELUtil.getIContainerParent(modelObject); | |
// } | |
// return null; | |
// } | |
// | |
// /** | |
// * Returns the EditPart which should act as the target for a given Link object. | |
// * (this depends on the collapsed/expanded state..its basically the target Activity | |
// * itself, or its innermost enclosing container, which is actually visible) | |
// */ | |
// public static EditPart getActingTargetEditPart(EditPartViewer viewer, Link link) { | |
// EObject modelObject = getLinkTarget(link); | |
// while (modelObject != null) { | |
// EditPart editPart = (EditPart)viewer.getEditPartRegistry().get(modelObject); | |
// if (editPart != null) return editPart; | |
// modelObject = BPELUtil.getIContainerParent(modelObject); | |
// } | |
// return null; | |
// } | |
// | |
// /** | |
// * Return all the links for which a collapsed edit part should act as the source, | |
// * even though it really isn't. (Because the *actual* sources are contained in | |
// * the edit part). | |
// */ | |
// public static List getAllContainedSourceLinks(EObject model) { | |
// List result = new ArrayList(); | |
// for (TreeIterator it = model.eAllContents(); it.hasNext(); ) { | |
// Object object = it.next(); | |
// // Activity *contains* the Sources which *contains* the Source | |
// if (object instanceof Source) { | |
// Link link = ((Source)object).getLink(); | |
// if (link != null) result.add(link); | |
// } | |
// } | |
// return result; | |
// } | |
// | |
// /** | |
// * Return all the links for which a collapsed edit part should act as the source, | |
// * even though it really isn't. (Because the *actual* sources are contained in | |
// * the edit part). | |
// */ | |
// public static List getAllContainedTargetLinks(EObject model) { | |
// List result = new ArrayList(); | |
// for (TreeIterator it = model.eAllContents(); it.hasNext(); ) { | |
// Object object = it.next(); | |
// // Activity *contains* the Sources which *contains* the Source | |
// if (object instanceof Source) { | |
// Link link = ((Source)object).getLink(); | |
// if (link != null) result.add(link); | |
// } | |
// } | |
// return result; | |
// } | |
} |