source: trunk/autoquest-plugin-uml/src/main/java/de/ugoe/cs/autoquest/plugin/uml/UMLUtils.java @ 1752

Last change on this file since 1752 was 1752, checked in by sherbold, 10 years ago
  • updated UMLUtils.createInteractionFromEventSequence to be compatible with the MIDAS DSL
  • Property svn:mime-type set to text/plain
File size: 20.8 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.plugin.uml;
16
17import java.util.Collection;
18import java.util.HashMap;
19import java.util.Iterator;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23import java.util.Map.Entry;
24
25import org.eclipse.emf.common.util.EList;
26import org.eclipse.uml2.uml.Comment;
27import org.eclipse.uml2.uml.Component;
28import org.eclipse.uml2.uml.Connector;
29import org.eclipse.uml2.uml.ConnectorEnd;
30import org.eclipse.uml2.uml.Element;
31import org.eclipse.uml2.uml.Interaction;
32import org.eclipse.uml2.uml.InteractionFragment;
33import org.eclipse.uml2.uml.Interface;
34import org.eclipse.uml2.uml.Lifeline;
35import org.eclipse.uml2.uml.Message;
36import org.eclipse.uml2.uml.MessageOccurrenceSpecification;
37import org.eclipse.uml2.uml.MessageSort;
38import org.eclipse.uml2.uml.Model;
39import org.eclipse.uml2.uml.Operation;
40import org.eclipse.uml2.uml.Port;
41import org.eclipse.uml2.uml.Region;
42import org.eclipse.uml2.uml.StateMachine;
43import org.eclipse.uml2.uml.Transition;
44import org.eclipse.uml2.uml.UMLPackage;
45import org.eclipse.uml2.uml.Vertex;
46
47import de.ugoe.cs.autoquest.eventcore.Event;
48import de.ugoe.cs.autoquest.plugin.http.eventcore.SOAPEventType;
49import de.ugoe.cs.autoquest.plugin.http.eventcore.SimpleSOAPEventType;
50import de.ugoe.cs.autoquest.plugin.uml.eventcore.UMLTransitionType;
51import de.ugoe.cs.autoquest.usageprofiles.TrieBasedModel;
52
53/**
54 * <p>
55 * Utilities for working with UML.
56 * </p>
57 *
58 * @author Steffen Herbold
59 */
60public class UMLUtils {
61
62    /**
63     * <p>
64     * Creates a sequence of events with {@link UMLTransitionType} as event type from a given
65     * sequence of events with the {@link SOAPEventType}, by matching the sequences to a state
66     * machine.
67     * </p>
68     *
69     * @param sequence
70     *            SOAP sequences
71     * @param stateMachine
72     *            the state machine
73     * @return create UML sequences
74     */
75    public static List<Event> createUMLTransitionSequence(List<Event> sequence,
76                                                          StateMachine stateMachine)
77    {
78        List<List<Transition>> matchingSequences =
79            determineMatchingTransitionSequences(sequence, stateMachine);
80
81        if (matchingSequences.size() != 1) {
82            throw new RuntimeException("no unique match found; " + matchingSequences.size() +
83                " matches");
84        }
85        List<Event> umlEventSequence = new LinkedList<>();
86        for (Transition transition : matchingSequences.get(0)) {
87            umlEventSequence.add(new Event(new UMLTransitionType(transition)));
88        }
89        return umlEventSequence;
90    }
91
92    /**
93     * <p>
94     * Uses a sequences of events with the {@link UMLTransitionType} to determine the transition
95     * probabilities for the state machine.
96     * </p>
97     *
98     * @param sequences
99     *            UML sequences
100     * @param stateMachine
101     *            state machine to be converted to a usage profile
102     */
103    public static void convertStateMachineToUsageProfile(Collection<List<Event>> sequences,
104                                                         StateMachine stateMachine)
105    {
106        // create state->outgoings hashmap
107        Map<Vertex, Map<Transition, Integer>> stateMap = new HashMap<>();
108        for (Region region : stateMachine.getRegions()) {
109            for (Vertex state : region.getSubvertices()) {
110                stateMap.put(state, new HashMap<Transition, Integer>());
111            }
112        }
113
114        // create counters for each transition
115        for (List<Event> sequence : sequences) {
116            for (Event event : sequence) {
117                if (event.getType() instanceof UMLTransitionType) {
118                    Transition transition = ((UMLTransitionType) event.getType()).getTransition();
119                    Map<Transition, Integer> transitionMap = stateMap.get(transition.getSource());
120                    Integer value = transitionMap.get(transition);
121                    if (value == null) {
122                        value = 0;
123                    }
124                    transitionMap.put(transition, value + 1);
125                }
126                else {
127                    throw new RuntimeException(
128                                               "Wrong event type. Only UMLTransitionType supported but was: " +
129                                                   event.getType().getClass().getName());
130                }
131            }
132        }
133
134        // calculate probabilities
135        for (Region region : stateMachine.getRegions()) {
136            for (Vertex state : region.getSubvertices()) {
137                Map<Transition, Integer> transitionMap = stateMap.get(state);
138                int totalCount = 0;
139                for (Entry<Transition, Integer> entry : transitionMap.entrySet()) {
140                    totalCount += entry.getValue();
141                }
142                if (totalCount != 0) {
143                    for (Transition transition : state.getOutgoings()) {
144                        double prob = 0.0d;
145                        if (transitionMap.containsKey(transition)) {
146                            prob = ((double) transitionMap.get(transition)) / totalCount;
147                        }
148                        Comment comment = transition.createOwnedComment();
149                        comment.setBody("" + prob);
150                    }
151                }
152                else {
153                    // system has never been in this state, all transitions equally likely
154                    int numOutgoings = state.getOutgoings().size();
155                    for (Transition transition : state.getOutgoings()) {
156                        Comment comment = transition.createOwnedComment();
157                        comment.setBody("" + (1.0d / numOutgoings));
158                    }
159                }
160            }
161        }
162    }
163
164    /**
165     * <p>
166     * Determines all matching {@link Transition} sequences in a state machine for a given sequence
167     * of SOAP events.
168     * </p>
169     *
170     * @param sequence
171     *            SOAP sequence
172     * @param stateMachine
173     *            the state machine
174     * @return all matching {@link Transition} sequences
175     */
176    public static List<List<Transition>> determineMatchingTransitionSequences(List<Event> sequence,
177                                                                              StateMachine stateMachine)
178    {
179        EList<Region> regions = stateMachine.getRegions();
180        EList<Vertex> states = null;
181        for (Region region : regions) {
182            if (states == null) {
183                states = region.getSubvertices();
184            }
185            else {
186                states.addAll(region.getSubvertices());
187            }
188        }
189        List<Transition> allTransitions = new LinkedList<>();
190        for (Vertex state : states) {
191            allTransitions.addAll(state.getOutgoings());
192        }
193
194        List<List<Transition>> matchingSequences = null;
195        List<Transition> currentTransitions = null;
196
197        // first, we try to find a single unique transition that we can match using the method name
198        for (Iterator<Event> eventIterator = sequence.iterator(); eventIterator.hasNext();) {
199            Event event = eventIterator.next();
200            if (event.getType() instanceof SOAPEventType) {
201                SOAPEventType eventType = (SOAPEventType) event.getType();
202                if (matchingSequences == null) {
203                    matchingSequences = new LinkedList<>();
204                    List<Transition> initialMatches = matchTransitions(allTransitions, eventType);
205                    for (Transition transition : initialMatches) {
206                        List<Transition> candidate = new LinkedList<>();
207                        candidate.add(transition);
208                        matchingSequences.add(candidate);
209                    }
210                    currentTransitions = initialMatches;
211                }
212                else {
213                    List<List<Transition>> nextMatchingSequences = new LinkedList<>();
214                    List<Transition> nextCurrentTransitions = new LinkedList<>();
215                    Iterator<Transition> currentTransitionIterator = currentTransitions.iterator();
216                    Iterator<List<Transition>> currentMatchingSequencesIterator =
217                        matchingSequences.iterator();
218                    while (currentTransitionIterator.hasNext()) {
219                        Transition currentTransition = currentTransitionIterator.next();
220                        List<Transition> currentMatch = currentMatchingSequencesIterator.next();
221
222                        List<Transition> matches =
223                            matchTransitions(currentTransition.getTarget().getOutgoings(),
224                                             eventType);
225                        if (matches.isEmpty()) {
226                            throw new RuntimeException("no matches found");
227                        }
228                        for (Transition matchingTransition : matches) {
229                            List<Transition> candidate = new LinkedList<>(currentMatch);
230                            candidate.add(matchingTransition);
231                            nextMatchingSequences.add(candidate);
232                            nextCurrentTransitions.add(matchingTransition);
233                        }
234                    }
235                    matchingSequences = nextMatchingSequences;
236                    currentTransitions = nextCurrentTransitions;
237                }
238            }
239            else {
240                throw new RuntimeException(
241                                           "Wrong event type. Only UMLTransitionType supported but was: " +
242                                               event.getType().getClass().getName());
243            }
244        }
245        return matchingSequences;
246    }
247
248    /**
249     * <p>
250     * Extends a given model with an interaction that represents an observed sequence.
251     * </p>
252     *
253     * @param sequence
254     *            sequence that is added as sequence diagram
255     * @param model
256     *            UML model to which the interaction is added
257     * @param interactionName
258     *            name of the interaction
259     */
260    public static void createInteractionFromEventSequence(List<Event> sequence,
261                                                          Model model,
262                                                          String interactionName)
263    {
264        Map<String, Interface> interfaceMap = new HashMap<>();
265        Map<String, Port> portMap = new HashMap<>();
266
267        EList<Element> elements = model.getOwnedElements();
268        for (Element element : elements) {
269            if (element instanceof Interface) {
270                interfaceMap.put(((Interface) element).getName(), (Interface) element);
271            }
272        }
273
274        Interaction interaction =
275            (Interaction) model.createPackagedElement(interactionName,
276                                                      UMLPackage.Literals.INTERACTION);
277
278        Lifeline userLifeline = interaction.createLifeline("user");
279       
280        Component testContext = (Component) model.getPackagedElement("TestContext", true, UMLPackage.Literals.COMPONENT, true);
281        userLifeline.setRepresents(testContext.getAttribute("user", null));
282       
283        Component userComponent = (Component) model.getPackagedElement("User", true, UMLPackage.Literals.COMPONENT, true);
284        Port userPort = (Port) userComponent.getAttribute("p_user_rlus", null);
285       
286        int i = 0;
287        for (Event event : sequence) {
288            if (!(event.equals(Event.STARTEVENT) || event.equals(Event.ENDEVENT))) {
289                String serviceName = getServiceNameFromEvent(event);
290                String methodName = getCalledMethodFromEvent(event);
291
292                Interface targetInterface = interfaceMap.get(serviceName);
293                if (targetInterface == null) {
294                    throw new RuntimeException(
295                                               "Could not find interface in the UML model that belong to the service: " +
296                                                   serviceName);
297                }
298
299                Lifeline targetLifeline = interaction.getLifeline(serviceName);
300                if (targetLifeline == null) {
301                    targetLifeline = interaction.createLifeline(serviceName);
302                   
303                   
304                    targetLifeline.setRepresents(testContext.getAttribute(serviceName+"_property", null));
305
306                    Component component = (Component) model.getPackagedElement(serviceName, true, UMLPackage.Literals.COMPONENT, true);
307                    portMap.put(serviceName, (Port) component.getAttribute("p_" + serviceName, null));
308                }
309                MessageOccurrenceSpecification sendFragment =
310                    (MessageOccurrenceSpecification) interaction
311                        .createFragment(i + ":" + methodName + "_sendFragment",
312                                        UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION);
313                MessageOccurrenceSpecification recvFragment =
314                    (MessageOccurrenceSpecification) interaction
315                        .createFragment(i + ":" + methodName + "_recvFragment",
316                                        UMLPackage.Literals.MESSAGE_OCCURRENCE_SPECIFICATION);
317
318                sendFragment.setCovered(userLifeline);
319                recvFragment.setCovered(targetLifeline);
320
321                Message message = interaction.createMessage(methodName);
322                if( getOperationFromName(targetInterface.getOperations(), methodName)==null ) {
323                    System.out.println("operation not found: " + methodName);
324                }
325                message.setSignature(getOperationFromName(targetInterface.getOperations(), methodName));
326                message.setMessageSort(MessageSort.ASYNCH_CALL_LITERAL);
327                message.setSendEvent(sendFragment);
328                message.setReceiveEvent(recvFragment);
329                               
330                EList<ConnectorEnd> sourceEnds = userPort.getEnds();
331                EList<ConnectorEnd> targetEnds = portMap.get(serviceName).getEnds();
332               
333                for( ConnectorEnd sourceEnd : sourceEnds ) {
334                    Connector sourceConnector = (Connector) sourceEnd.eContainer();
335                    for( ConnectorEnd targetEnd : targetEnds ) {
336                        Connector targetConnector =  (Connector) targetEnd.eContainer();
337                        if( targetConnector==sourceConnector ) {
338                            message.setConnector(targetConnector);
339                        }
340                    }
341                }               
342               
343                sendFragment.setMessage(message);
344                recvFragment.setMessage(message);
345
346                i++;
347            }
348        }
349    }
350
351    /**
352     * <p>
353     * Calculates the usage score of an interaction as the logsum of the event probabilities
354     * multiplied with the length of the interaction.
355     * </p>
356     *
357     * @param interaction
358     *            interaction for which the score is calculated
359     * @param usageProfile
360     *            usage profile used for the calculation
361     * @return calculated usage score
362     */
363    public static double calculateUsageScore(Interaction interaction, TrieBasedModel usageProfile) {
364        double usageScore = 0.0d;
365
366        EList<InteractionFragment> interactionFragments = interaction.getFragments();
367        List<Event> eventSequence = new LinkedList<>();
368        eventSequence.add(Event.STARTEVENT);
369        for (InteractionFragment interactionFragment : interactionFragments) {
370            if (interactionFragment.getName() != null &&
371                interactionFragment.getName().endsWith("_recvFragment"))
372            {
373                String serviceName =
374                    interactionFragment.getCovereds().get(0).getRepresents().getName();
375                String methodName = "UNKNOWN";
376                if (interactionFragment instanceof MessageOccurrenceSpecification) {
377                    methodName =
378                        ((MessageOccurrenceSpecification) interactionFragment).getMessage()
379                            .getName();
380                }
381                eventSequence.add(new Event(new SimpleSOAPEventType(methodName, serviceName)));
382            }
383        }
384        double prob = usageProfile.getLogSum(eventSequence);
385        usageScore = prob * eventSequence.size();
386
387        return usageScore;
388    }
389
390    /**
391     * <p>
392     * Helper function to get the name of a service from a SOAP event.
393     * </p>
394     *
395     * @param event
396     *            event for which the service name is retrieved
397     * @return service name
398     */
399    private static String getServiceNameFromEvent(Event event) {
400        if (event.getType() instanceof SOAPEventType) {
401            return ((SOAPEventType) event.getType()).getServiceName();
402        }
403        else if (event.getType() instanceof SimpleSOAPEventType) {
404            return ((SimpleSOAPEventType) event.getType()).getServiceName();
405        }
406        else {
407            throw new RuntimeException(
408                                       "Wrong event type. Only SOAPEventType and SimpleSOAPEventType supported but was: " +
409                                           event.getType().getClass().getName());
410        }
411    }
412
413    /**
414     *
415     * <p>
416     * Helper function to get the called method from a SOAP event
417     * </p>
418     *
419     * @param event
420     *            event for which the called method is retrieved
421     * @return called method
422     */
423    private static String getCalledMethodFromEvent(Event event) {
424        if (event.getType() instanceof SOAPEventType) {
425            return ((SOAPEventType) event.getType()).getCalledMethod();
426        }
427        else if (event.getType() instanceof SimpleSOAPEventType) {
428            return ((SimpleSOAPEventType) event.getType()).getCalledMethod();
429        }
430        else {
431            throw new RuntimeException(
432                                       "Wrong event type. Only SOAPEventType and SimpleSOAPEventType supported but was: " +
433                                           event.getType().getClass().getName());
434        }
435    }
436
437    /**
438     * <p>
439     * Fetches an operation using only its name from a list of operations. Returns the first match
440     * found or null if no match is found.
441     * </p>
442     *
443     * @param operations
444     *            list of operations
445     * @param name
446     *            name of the operation
447     * @return first matching operation; null if no match is found
448     */
449    private static Operation getOperationFromName(EList<Operation> operations, String name) {
450        if (name == null) {
451            throw new IllegalArgumentException("name of the operation must not be null");
452        }
453        if (operations != null) {
454            for (Operation operation : operations) {
455                if (operation.getName() != null && operation.getName().equals(name)) {
456                    return operation;
457                }
458            }
459        }
460        return null;
461    }
462
463    /**
464     * <p>
465     * Determines which transitions match a given {@link SOAPEventType}.
466     * </p>
467     *
468     * @param transitions
469     *            the transitions
470     * @param eventType
471     *            the SOAP event
472     * @return matching transitions
473     */
474    private static List<Transition> matchTransitions(List<Transition> transitions,
475                                                     SOAPEventType eventType)
476    {
477        List<Transition> matching = new LinkedList<>();
478        for (Transition transition : transitions) {
479            // String serviceName = transition.getName().split("\\.")[0]; // TODO service name check
480            String methodName = transition.getName().split("\\.")[1];
481            if (methodName.equals(eventType.getCalledMethod())) {
482                matching.add(transition);
483            }
484        }
485        return matching;
486    }
487
488}
Note: See TracBrowser for help on using the repository browser.