// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.plugin.uml; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.logging.Level; import java.util.Set; import java.util.TreeSet; import org.eclipse.emf.common.util.EList; import org.eclipse.uml2.uml.Activity; import org.eclipse.uml2.uml.ActivityEdge; import org.eclipse.uml2.uml.ActivityNode; import org.eclipse.uml2.uml.CallConcurrencyKind; import org.eclipse.uml2.uml.CallOperationAction; import org.eclipse.uml2.uml.Comment; import org.eclipse.uml2.uml.Component; import org.eclipse.uml2.uml.Connector; import org.eclipse.uml2.uml.ConnectorEnd; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Interaction; import org.eclipse.uml2.uml.InteractionFragment; import org.eclipse.uml2.uml.Interface; import org.eclipse.uml2.uml.Lifeline; import org.eclipse.uml2.uml.Message; import org.eclipse.uml2.uml.MessageOccurrenceSpecification; import org.eclipse.uml2.uml.MessageSort; import org.eclipse.uml2.uml.Model; import org.eclipse.uml2.uml.Operation; import org.eclipse.uml2.uml.Package; import org.eclipse.uml2.uml.Port; import org.eclipse.uml2.uml.Profile; import org.eclipse.uml2.uml.Property; import org.eclipse.uml2.uml.Region; import org.eclipse.uml2.uml.StateMachine; import org.eclipse.uml2.uml.Stereotype; import org.eclipse.uml2.uml.Transition; import org.eclipse.uml2.uml.UMLPackage; import org.eclipse.uml2.uml.Vertex; import de.ugoe.cs.autoquest.eventcore.Event; import de.ugoe.cs.autoquest.plugin.http.eventcore.SOAPEventType; import de.ugoe.cs.autoquest.plugin.http.eventcore.SimpleSOAPEventType; import de.ugoe.cs.autoquest.plugin.uml.eventcore.UMLTransitionType; import de.ugoe.cs.autoquest.usageprofiles.IStochasticProcess; import de.ugoe.cs.util.console.Console; /** *

* Utilities for working with UML. *

* * @author Steffen Herbold */ public class UMLUtils { public static void validateModelWithLog(Collection> sequences, Model model, String testContextName) { final Profile utpProfile = model.getAppliedProfile("utp"); final Stereotype utpTestComponent = (Stereotype) utpProfile.getOwnedMember("TestComponent"); final Stereotype utpSUT = (Stereotype) utpProfile.getOwnedMember("SUT"); final Stereotype utpTestContext = (Stereotype) utpProfile.getOwnedMember("TestContext"); Component testContext = fetchTestContext(model, utpTestContext, testContextName); if (testContext == null) { if( testContextName==null ) { Console.traceln(Level.SEVERE, "Could not find any TestContext in the model."); } else { Console.traceln(Level.SEVERE, "Could not find TestContext in the model: " + testContextName); } Console.traceln(Level.SEVERE, "Hint: Check if you have applied the TestContext stereotype correctly in the model."); } // Create list of unique methods calls HashMap> calledMethods = new HashMap<>(); for( List sequence : sequences ) { for( Event event : sequence ) { if( event.getType() instanceof SOAPEventType ) { SOAPEventType eventType = (SOAPEventType) event.getType(); Set curCalledMethods = calledMethods.get(eventType.getServiceName()); if( curCalledMethods==null ) { curCalledMethods = new TreeSet<>(); calledMethods.put(eventType.getServiceName(), curCalledMethods); } curCalledMethods.add(eventType.getCalledMethod()); } } } Console.traceln(Level.INFO, "Found the following services and operations in the usage data: "); for( Entry> entry : calledMethods.entrySet() ) { Console.traceln(Level.INFO, "\tService \"" + entry.getKey() + "\": "); Iterator iter = entry.getValue().iterator(); StringBuilder strBld = new StringBuilder(); while (iter.hasNext()) { strBld.append(iter.next()); if (iter.hasNext()) { strBld.append(", "); } } Console.traceln(Level.INFO, strBld.toString()); } // fetch all SUTs and TestComponents HashMap properties = new HashMap<>(); for (Property property : testContext.getAllAttributes()) { if (property.getAppliedStereotypes().contains(utpSUT)) { properties.put(property.getName(),property); } else if (property.getType().getAppliedStereotypes().contains(utpTestComponent)) { properties.put(property.getName(),property); } } Console.traceln(Level.INFO, "Found the following services in the TestConfiguration:"); for( Entry entry : properties.entrySet() ) { Console.traceln(Level.INFO, "\t" + entry.getKey()); } for( Entry> entry : calledMethods.entrySet() ) { String serviceName = entry.getKey(); Console.traceln(Level.INFO, "Checking service: " + serviceName); Set methodNames = entry.getValue(); Property property = properties.get(serviceName); if( property==null ) { Console.traceln(Level.SEVERE, "\tCould not find property for service: " + serviceName); Console.traceln(Level.SEVERE, "\tHint: Check service name map and/or model if the service is present and spelled correctly."); Console.traceln(Level.SEVERE, "\tHint: Check if the SUT/TestComponent stereotype has been applied correctly in this TestContext."); } else { Set interfaces = getRealizedInterfacesFromProperty(property); if( interfaces.isEmpty() ) { Console.traceln(Level.SEVERE, "\tCould not find any interfaces implementing the property for service: " + serviceName); Console.traceln(Level.SEVERE, "\tHint: Check if the property correctly realizes the interfaces in the model."); } else { Console.traceln(Level.INFO, "\tFound the following realized interfaces for the service \"" + serviceName + "\": "); Iterator iter = interfaces.iterator(); while (iter.hasNext()) { String interfaceName = iter.next().getName(); StringBuilder strBld = new StringBuilder(); strBld.append(interfaceName); if (iter.hasNext()) { strBld.append(", "); } Console.traceln(Level.INFO, strBld.toString()); } for( String methodName : methodNames ) { boolean methodFound = true; for( Interface intface : interfaces ) { if (getOperationFromName(intface.getOperations(), methodName) != null) { // interface found Console.traceln(Level.INFO, "\tMethod " + methodName + " found in interface " + intface.getName() ); methodFound = true; } } if( !methodFound ) { Console.traceln(Level.SEVERE, "\tCould not find operation: " + methodName); Console.traceln(Level.SEVERE, "\tHint: check if operation is present and spelled correctly"); } } } } } } /** *

* Creates a sequence of events with {@link UMLTransitionType} as event type from a given * sequence of events with the {@link SOAPEventType}, by matching the sequences to a state * machine. *

* * @param sequence * SOAP sequences * @param stateMachine * the state machine * @return create UML sequences */ public static List createUMLTransitionSequence(List sequence, StateMachine stateMachine) { List> matchingSequences = determineMatchingTransitionSequences(sequence, stateMachine); if (matchingSequences.size() != 1) { throw new RuntimeException("no unique match found; " + matchingSequences.size() + " matches"); } List umlEventSequence = new LinkedList<>(); for (Transition transition : matchingSequences.get(0)) { umlEventSequence.add(new Event(new UMLTransitionType(transition))); } return umlEventSequence; } /** *

* Uses a sequences of events with the {@link UMLTransitionType} to determine the transition * probabilities for the state machine. *

* * @param sequences * UML sequences * @param stateMachine * state machine to be converted to a usage profile */ public static void convertStateMachineToUsageProfile(Collection> sequences, StateMachine stateMachine) { // create state->outgoings hashmap Map> stateMap = new HashMap<>(); for (Region region : stateMachine.getRegions()) { for (Vertex state : region.getSubvertices()) { stateMap.put(state, new HashMap()); } } // create counters for each transition for (List sequence : sequences) { for (Event event : sequence) { if (event.getType() instanceof UMLTransitionType) { Transition transition = ((UMLTransitionType) event.getType()).getTransition(); Map transitionMap = stateMap.get(transition.getSource()); Integer value = transitionMap.get(transition); if (value == null) { value = 0; } transitionMap.put(transition, value + 1); } else { throw new RuntimeException( "Wrong event type. Only UMLTransitionType supported but was: " + event.getType().getClass().getName()); } } } // calculate probabilities for (Region region : stateMachine.getRegions()) { for (Vertex state : region.getSubvertices()) { Map transitionMap = stateMap.get(state); int totalCount = 0; for (Entry entry : transitionMap.entrySet()) { totalCount += entry.getValue(); } if (totalCount != 0) { for (Transition transition : state.getOutgoings()) { double prob = 0.0d; if (transitionMap.containsKey(transition)) { prob = ((double) transitionMap.get(transition)) / totalCount; } Comment comment = transition.createOwnedComment(); comment.setBody("" + prob); } } else { // system has never been in this state, all transitions equally likely int numOutgoings = state.getOutgoings().size(); for (Transition transition : state.getOutgoings()) { Comment comment = transition.createOwnedComment(); comment.setBody("" + (1.0d / numOutgoings)); } } } } } /** *

* Determines all matching {@link Transition} sequences in a state machine for a given sequence * of SOAP events. *

* * @param sequence * SOAP sequence * @param stateMachine * the state machine * @return all matching {@link Transition} sequences */ public static List> determineMatchingTransitionSequences(List sequence, StateMachine stateMachine) { EList regions = stateMachine.getRegions(); EList states = null; for (Region region : regions) { if (states == null) { states = region.getSubvertices(); } else { states.addAll(region.getSubvertices()); } } List allTransitions = new LinkedList<>(); for (Vertex state : states) { allTransitions.addAll(state.getOutgoings()); } List> matchingSequences = null; List currentTransitions = null; // first, we try to find a single unique transition that we can match using the method name for (Iterator eventIterator = sequence.iterator(); eventIterator.hasNext();) { Event event = eventIterator.next(); if (event.getType() instanceof SOAPEventType) { SOAPEventType eventType = (SOAPEventType) event.getType(); if (matchingSequences == null) { matchingSequences = new LinkedList<>(); List initialMatches = matchTransitions(allTransitions, eventType); for (Transition transition : initialMatches) { List candidate = new LinkedList<>(); candidate.add(transition); matchingSequences.add(candidate); } currentTransitions = initialMatches; } else { List> nextMatchingSequences = new LinkedList<>(); List nextCurrentTransitions = new LinkedList<>(); Iterator currentTransitionIterator = currentTransitions.iterator(); Iterator> currentMatchingSequencesIterator = matchingSequences.iterator(); while (currentTransitionIterator.hasNext()) { Transition currentTransition = currentTransitionIterator.next(); List currentMatch = currentMatchingSequencesIterator.next(); List matches = matchTransitions(currentTransition.getTarget().getOutgoings(), eventType); if (matches.isEmpty()) { throw new RuntimeException("no matches found"); } for (Transition matchingTransition : matches) { List candidate = new LinkedList<>(currentMatch); candidate.add(matchingTransition); nextMatchingSequences.add(candidate); nextCurrentTransitions.add(matchingTransition); } } matchingSequences = nextMatchingSequences; currentTransitions = nextCurrentTransitions; } } else { throw new RuntimeException( "Wrong event type. Only UMLTransitionType supported but was: " + event.getType().getClass().getName()); } } return matchingSequences; } /** *

* Extends a given model with an interaction that represents an observed sequence. *

* * @param sequence * sequence that is added as sequence diagram * @param model * UML model to which the interaction is added * @param interactionName * name of the interaction * @param testContextName * Name of the test context that should be used. If this value is null, the first * test context found is used. */ public static void createInteractionFromEventSequence(List sequence, Model model, String interactionName, String testContextName) { final Profile utpProfile = model.getAppliedProfile("utp"); final Stereotype utpTestCase = (Stereotype) utpProfile.getOwnedMember("TestCase"); final Stereotype utpTestComponent = (Stereotype) utpProfile.getOwnedMember("TestComponent"); final Stereotype utpSUT = (Stereotype) utpProfile.getOwnedMember("SUT"); final Stereotype utpTestContext = (Stereotype) utpProfile.getOwnedMember("TestContext"); Component testContext = fetchTestContext(model, utpTestContext, testContextName); if (testContext == null) { throw new RuntimeException("Could not find any test context in the model"); } Operation operation = testContext.createOwnedOperation(interactionName, null, null); operation.applyStereotype(utpTestCase); Interaction interaction = (Interaction) testContext.createPackagedElement(interactionName + "_Impl", UMLPackage.Literals.INTERACTION); operation.getMethods().add(interaction); // create lifelines Lifeline userLifeline = null; for (Property property : testContext.getAllAttributes()) { if (property.getAppliedStereotypes().contains(utpSUT)) { String serviceName = property.getName(); Lifeline targetLifeline = interaction.createLifeline(serviceName); targetLifeline.setRepresents(property); } else if (property.getType().getAppliedStereotypes().contains(utpTestComponent)) { if( userLifeline!=null ) { throw new RuntimeException("TestContext must only have one TestComponent for the application of usage-based testing."); } userLifeline = interaction.createLifeline(property.getName()); userLifeline.setRepresents(property); } } if( userLifeline==null ) { throw new RuntimeException("No TestComponent found, could not create user lifeline."); } if( interaction.getLifelines().size()<2 ) { throw new RuntimeException("Fewer than two lifelines created. No SUT found."); } int i = 0; for (Event event : sequence) { if (!(event.equals(Event.STARTEVENT) || event.equals(Event.ENDEVENT))) { String serviceName = getServiceNameFromEvent(event); String methodName = getCalledMethodFromEvent(event); // determine lifelines Lifeline msgTargetLifeline; Lifeline msgSourceLifeline; if (serviceName.equals(userLifeline.getName())) { // message being send to user // currently we just select the first lifeline that is not the user // this, obviously, has to be replaced with the real service. // however, identification of the source of a message is still an open issue msgSourceLifeline = null; for (Lifeline lifeline : interaction.getLifelines()) { if (!lifeline.equals(userLifeline)) { msgSourceLifeline = lifeline; break; } } msgTargetLifeline = userLifeline; } else { msgSourceLifeline = userLifeline; msgTargetLifeline = interaction.getLifeline(serviceName); } if( msgSourceLifeline==null ) { throw new RuntimeException("Error creating message: could not determine source lifeline."); } if( msgTargetLifeline==null ) { throw new RuntimeException("Error creating message: could not determine target lifeline."); } // determine correct target interface Set targetInterfaces = getRealizedInterfacesFromProperty((Property) msgTargetLifeline.getRepresents()); if (targetInterfaces.isEmpty()) { throw new RuntimeException("no interface associated with the property " + msgTargetLifeline.getRepresents().getName()); } Interface targetInterface = null; for (Interface intface : targetInterfaces) { if (getOperationFromName(intface.getOperations(), methodName) != null) { // interface found targetInterface = intface; break; } } if (targetInterface == null) { StringBuilder errStrBuilder = new StringBuilder(); errStrBuilder.append("Error creating message: operation not found in the implementing interfaces ("); Iterator iter = targetInterfaces.iterator(); while (iter.hasNext()) { String interfaceName = iter.next().getName(); errStrBuilder.append(interfaceName); if (iter.hasNext()) { errStrBuilder.append(","); } else { errStrBuilder.append("): " + methodName); } } throw new RuntimeException(errStrBuilder.toString()); } Operation calledOperation = getOperationFromName(targetInterface.getOperations(), methodName); // setup for both SYNCH and ASYNCH calls MessageOccurrenceSpecification callSendFragment = (MessageOccurrenceSpecification) interaction .createFragment(i + ":" + methodName + "_callSendFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); MessageOccurrenceSpecification callRecvFragment = (MessageOccurrenceSpecification) interaction .createFragment(i + ":" + methodName + "_callRecvFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); callSendFragment.setCovered(msgSourceLifeline); callRecvFragment.setCovered(msgTargetLifeline); // create call Message callMessage = interaction.createMessage(methodName); callMessage.setSignature(calledOperation); callMessage.setConnector(inferConnector(msgSourceLifeline, msgTargetLifeline)); callMessage.setSendEvent(callSendFragment); callMessage.setReceiveEvent(callRecvFragment); callSendFragment.setMessage(callMessage); callRecvFragment.setMessage(callMessage); boolean asynch = false; if( calledOperation.getConcurrency()==CallConcurrencyKind.CONCURRENT_LITERAL ) { asynch = true; } if (asynch) { // Create ASYNCH call callMessage.setMessageSort(MessageSort.ASYNCH_CALL_LITERAL); } else { // SYNCH call callMessage.setMessageSort(MessageSort.SYNCH_CALL_LITERAL); // setup reply and behavior execution specifications MessageOccurrenceSpecification replySendFragment = (MessageOccurrenceSpecification) interaction .createFragment(i + ":" + methodName + "_replySendFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); MessageOccurrenceSpecification replyRecvFragment = (MessageOccurrenceSpecification) interaction .createFragment(i + ":" + methodName + "_replyRecvFragment", UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION); replySendFragment.setCovered(msgTargetLifeline); replyRecvFragment.setCovered(msgSourceLifeline); /*BehaviorExecutionSpecification sourceBehaviorExecutionSpecification = (BehaviorExecutionSpecification) interaction .createFragment(":" + methodName + "_sourceBhvExecSpec", UMLPackage.Literals.BEHAVIOR_EXECUTION_SPECIFICATION); BehaviorExecutionSpecification targetBehaviorExecutionSpecification = (BehaviorExecutionSpecification) interaction .createFragment(":" + methodName + "_targetBhvExecSpec", UMLPackage.Literals.BEHAVIOR_EXECUTION_SPECIFICATION); sourceBehaviorExecutionSpecification.setStart(callSendFragment); sourceBehaviorExecutionSpecification.setFinish(replyRecvFragment); targetBehaviorExecutionSpecification.setStart(callRecvFragment); targetBehaviorExecutionSpecification.setFinish(replySendFragment);*/ // create reply Message replyMessage = interaction.createMessage(methodName + "_reply"); replyMessage.setMessageSort(MessageSort.REPLY_LITERAL); replyMessage.setSignature(calledOperation); replyMessage.setSendEvent(replySendFragment); replyMessage.setReceiveEvent(replyRecvFragment); replySendFragment.setMessage(replyMessage); replyRecvFragment.setMessage(replyMessage); } i++; } } } /** *

* Calculates the usage score of an interaction as the logsum of the event probabilities * multiplied with the length of the interaction. *

* * @param interaction * interaction for which the score is calculated * @param usageProfile * usage profile used for the calculation * @return calculated usage score */ public static double calculateUsageScore(Interaction interaction, IStochasticProcess usageProfile) { double usageScore = 0.0d; EList interactionFragments = interaction.getFragments(); List eventSequence = new LinkedList<>(); eventSequence.add(Event.STARTEVENT); for (InteractionFragment interactionFragment : interactionFragments) { if (interactionFragment.getName() != null && interactionFragment.getName().endsWith("_recvFragment")) // TODO must be more // generic { String serviceName = interactionFragment.getCovereds().get(0).getRepresents().getName().split("_")[0]; String methodName = "UNKNOWN"; if (interactionFragment instanceof MessageOccurrenceSpecification) { methodName = ((MessageOccurrenceSpecification) interactionFragment).getMessage() .getName(); } eventSequence.add(new Event(new SimpleSOAPEventType(methodName, serviceName))); } } eventSequence.add(Event.ENDEVENT); double prob = usageProfile.getLogSum(eventSequence); usageScore = eventSequence.size() * prob; return usageScore; } /** *

* Extends the given model with an activity for usage-based scheduling of the test cases. *

* * @param model * model to be extended * @param usageProfile * usage profile used as foundation */ public static void createScheduling(Model model, IStochasticProcess usageProfile, String testContextName) { final Profile utpProfile = model.getAppliedProfile("utp"); final Stereotype utpTestCase = (Stereotype) utpProfile.getOwnedMember("TestCase"); final Stereotype utpTestContext = (Stereotype) utpProfile.getOwnedMember("TestContext"); Component testContext = fetchTestContext(model, utpTestContext, testContextName); if (testContext == null) { throw new RuntimeException("Could not find any test context in the model"); } Map usageScoreMapUnsorted = new HashMap<>(); // first, we determine all test cases and calculate their usage scores for (Operation operation : testContext.getAllOperations()) { if (operation.getAppliedStereotypes().contains(utpTestCase)) { Interaction interaction = (Interaction) operation.getMethods().get(0); usageScoreMapUnsorted .put(operation, calculateUsageScore(interaction, usageProfile)); } } Map usageScoreMapSorted = sortByValue(usageScoreMapUnsorted); // now we create the scheduling Activity schedulingActivity = (Activity) testContext.createOwnedBehavior("UsageBasedScheduling", UMLPackage.Literals.ACTIVITY); testContext.setClassifierBehavior(schedulingActivity); ActivityNode startNode = schedulingActivity.createOwnedNode("final", UMLPackage.Literals.INITIAL_NODE); ActivityNode finalNode = schedulingActivity.createOwnedNode("final", UMLPackage.Literals.ACTIVITY_FINAL_NODE); ActivityNode currentOperationNode = startNode; for (Entry entry : usageScoreMapSorted.entrySet()) { Operation operation = entry.getKey(); CallOperationAction nextOperationNode = (CallOperationAction) schedulingActivity .createOwnedNode(operation.getName(), UMLPackage.Literals.CALL_OPERATION_ACTION); nextOperationNode.setOperation(operation); ActivityEdge edge = schedulingActivity.createEdge(currentOperationNode.getName() + "_to_" + nextOperationNode.getName(), UMLPackage.Literals.CONTROL_FLOW); edge.setSource(currentOperationNode); edge.setTarget(nextOperationNode); currentOperationNode = nextOperationNode; } ActivityEdge edge = schedulingActivity .createEdge(currentOperationNode.getName() + "_to_" + finalNode.getName(), UMLPackage.Literals.CONTROL_FLOW); edge.setSource(currentOperationNode); edge.setTarget(finalNode); } /** * From * http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java * and adapted to do an inverse sorting */ public static > Map sortByValue(Map map) { List> list = new LinkedList<>(map.entrySet()); Collections.sort(list, new Comparator>() { @Override public int compare(Map.Entry o1, Map.Entry o2) { return -1 * (o1.getValue()).compareTo(o2.getValue()); } }); Map result = new LinkedHashMap<>(); for (Map.Entry entry : list) { result.put(entry.getKey(), entry.getValue()); } return result; } /** *

* Helper function to get the name of a service from a SOAP event. *

* * @param event * event for which the service name is retrieved * @return service name */ protected static String getServiceNameFromEvent(Event event) { if (event.getType() instanceof SOAPEventType) { return ((SOAPEventType) event.getType()).getServiceName(); } else if (event.getType() instanceof SimpleSOAPEventType) { return ((SimpleSOAPEventType) event.getType()).getServiceName(); } else { throw new RuntimeException( "Wrong event type. Only SOAPEventType and SimpleSOAPEventType supported but was: " + event.getType().getClass().getName()); } } /** * *

* Helper function to get the called method from a SOAP event *

* * @param event * event for which the called method is retrieved * @return called method */ private static String getCalledMethodFromEvent(Event event) { if (event.getType() instanceof SOAPEventType) { return ((SOAPEventType) event.getType()).getCalledMethod(); } else if (event.getType() instanceof SimpleSOAPEventType) { return ((SimpleSOAPEventType) event.getType()).getCalledMethod(); } else { throw new RuntimeException( "Wrong event type. Only SOAPEventType and SimpleSOAPEventType supported but was: " + event.getType().getClass().getName()); } } /** *

* Fetches an operation using only its name from a list of operations. Returns the first match * found or null if no match is found. *

* * @param operations * list of operations * @param name * name of the operation * @return first matching operation; null if no match is found */ private static Operation getOperationFromName(EList operations, String name) { if (name == null) { throw new IllegalArgumentException("name of the operation must not be null"); } if (operations != null) { for (Operation operation : operations) { if (operation.getName() != null && operation.getName().equals(name)) { return operation; } } } return null; } /** *

* Determines which transitions match a given {@link SOAPEventType}. *

* * @param transitions * the transitions * @param eventType * the SOAP event * @return matching transitions */ private static List matchTransitions(List transitions, SOAPEventType eventType) { List matching = new LinkedList<>(); for (Transition transition : transitions) { // String serviceName = transition.getName().split("\\.")[0]; // TODO service name check String methodName = transition.getName().split("\\.")[1]; if (methodName.equals(eventType.getCalledMethod())) { matching.add(transition); } } return matching; } private static Set getRealizedInterfacesFromProperty(Property property) { return getRealizedInterfaceFromComponent((Component) property.getType()); } private static Set getRealizedInterfaceFromComponent(Component comp) { Set interfaces = new HashSet<>(); // Interface myInterface = null; for (Property property : comp.getAttributes()) { if (property instanceof Port) { Port port = (Port) property; if (!port.isConjugated()) { interfaces.addAll(port.getProvideds()); } } } return interfaces; } private static Component fetchTestContext(Package pkg, Stereotype utpTestContext, String testContextName) { List testContexts = fetchTestContextRecursively(pkg, utpTestContext); if (testContexts.isEmpty()) { return null; } if (testContextName != null) { for (Component testContext : testContexts) { if (testContextName.equals(testContext.getName())) { return testContext; } } return null; } else { return testContexts.get(0); } } private static List fetchTestContextRecursively(Package pkg, Stereotype utpTestContext) { List testContexts = new LinkedList<>(); for (Element element : pkg.getOwnedElements()) { if (element instanceof Package) { testContexts.addAll(fetchTestContextRecursively((Package) element, utpTestContext)); } if (element instanceof Component && element.getAppliedStereotypes().contains(utpTestContext)) { testContexts.add((Component) element); } } return testContexts; } /** *

* Infers connector between two lifelines. * TODO: currently assumes only one connector between two lifelines possible. I need to make sure this assumption is valid. *

* * @param userAttributes * @param targetAttributes */ private static Connector inferConnector(Lifeline msgSourceLifeline, Lifeline msgTargetLifeline) { EList userAttributes = ((Component) msgSourceLifeline.getRepresents().getType()).getAttributes(); EList targetAttributes = ((Component) msgTargetLifeline.getRepresents().getType()).getAttributes(); for (Property userAttribute : userAttributes) { if (userAttribute instanceof Port) { EList userEnds = ((Port) userAttribute).getEnds(); for (ConnectorEnd userEnd : userEnds) { Connector userConnector = (Connector) userEnd.eContainer(); for (Property targetAttribute : targetAttributes) { if (targetAttribute instanceof Port) { EList targetEnds = ((Port) targetAttribute).getEnds(); for (ConnectorEnd targetEnd : targetEnds) { Connector targetConnector = (Connector) targetEnd.eContainer(); if (targetConnector == userConnector) { return targetConnector; } } } } } } } return null; } }