source: trunk/autoquest-plugin-http/src/main/java/de/ugoe/cs/autoquest/plugin/http/SOAPUtils.java @ 2210

Last change on this file since 2210 was 2010, checked in by sherbold, 9 years ago
  • updated interaction generation to be able to handle anonymous sequence and choice elements in the model that represent XSD sequences and choices to some degree. This is just a workaround at the current stage
  • interaction generation now supports enumeration data types
  • Property svn:mime-type set to text/plain
File size: 35.1 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.http;
16
17import java.io.StringWriter;
18import java.util.ArrayList;
19import java.util.Collection;
20import java.util.HashSet;
21import java.util.Iterator;
22import java.util.LinkedList;
23import java.util.List;
24import java.util.Set;
25import java.util.Stack;
26import java.util.logging.Level;
27
28import javax.xml.transform.Transformer;
29import javax.xml.transform.TransformerException;
30import javax.xml.transform.TransformerFactory;
31import javax.xml.transform.TransformerFactoryConfigurationError;
32import javax.xml.transform.dom.DOMSource;
33import javax.xml.transform.stream.StreamResult;
34
35import org.w3c.dom.Attr;
36import org.w3c.dom.Element;
37import org.w3c.dom.Node;
38import org.w3c.dom.NodeList;
39
40import de.ugoe.cs.autoquest.eventcore.Event;
41import de.ugoe.cs.autoquest.plugin.http.eventcore.EqualSOAPDataMap;
42import de.ugoe.cs.autoquest.plugin.http.eventcore.SOAPEventType;
43import de.ugoe.cs.autoquest.plugin.http.eventcore.SimpleSOAPEventType;
44import de.ugoe.cs.autoquest.plugin.http.eventcore.SimpleSOAPEventType.CallType;
45import de.ugoe.cs.util.console.Console;
46
47/**
48 * <p>
49 * Utilities for working with SOAP events. Their main task is to simply working with
50 * {@link SimpleSOAPEventType} and {@link SOAPEventType}.
51 * </p>
52 *
53 * @author Steffen Herbold
54 */
55public class SOAPUtils {
56
57    /**
58     * <p>
59     * Defines how sequences are ordered:
60     * <ul>
61     * <li>REQUEST: by the request order id</li>
62     * <li>RESPONSE: by the response order id</li>
63     * </ul>
64     * </p>
65     *
66     * @author Steffen Herbold
67     */
68    public enum SequenceOrder {
69        REQUEST, RESPONSE
70    }
71
72    /**
73     * <p>
74     * Replaces events with a {@link SOAPEventType} with new events of {@link SimpleSOAPEventType}
75     * and no target.
76     * </p>
77     *
78     * @param sequences
79     *            sequences where the events are replaced
80     * @param keepOnlySOAPEvents
81     *            if true, all events that are not of SOAPEventType or SimpleSOAPEventType are
82     *            removed
83     * @return sequences with {@link SimpleSOAPEventType}s instead of {@link SOAPEventType}s
84     */
85    public static Collection<List<Event>> convertToSimpleSOAPEvent(Collection<List<Event>> sequences,
86                                                                   boolean keepOnlySOAPEvents)
87    {
88        Collection<List<Event>> newSequences = new LinkedList<>();
89        EqualSOAPDataMap equalSOAPDataMap = new EqualSOAPDataMap();
90        for (List<Event> sequence : sequences) {
91            List<Event> newSequence = null;
92            if (sequence != null) {
93                newSequence = new LinkedList<>();
94                for (Event event : sequence) {
95                    if (event.getType() instanceof SOAPEventType) {
96                        SOAPEventType eventType = (SOAPEventType) event.getType();
97                        newSequence.add(new Event(new SimpleSOAPEventType(eventType
98                            .getCalledMethod(), eventType.getServiceName(), eventType
99                            .getClientName(), eventType.getSoapRequestBody(), equalSOAPDataMap,
100                                                                          CallType.REQUEST)));
101                    }
102                    else {
103                        if (!keepOnlySOAPEvents || event.getType() instanceof SimpleSOAPEventType) {
104                            newSequence.add(event);
105                        }
106                    }
107                }
108            }
109            newSequences.add(newSequence);
110        }
111        return newSequences;
112    }
113
114    /**
115     * <p>
116     * Removes all non SOAP events from the contained sequences
117     * </p>
118     *
119     * @param sequences
120     *            sequences where the events are replaced
121     */
122    public static Collection<List<Event>> removeNonSOAPEvents(Collection<List<Event>> sequences) {
123        Collection<List<Event>> soapOnlySequences = new LinkedList<>();
124        for (List<Event> sequence : sequences) {
125            soapOnlySequences.add(removeNonSOAPEvents(sequence));
126        }
127        return soapOnlySequences;
128    }
129
130    /**
131     * <p>
132     * Removes all non SOAP events from a sequence
133     * </p>
134     *
135     * @param sequence
136     *            sequence where the events are replaced
137     */
138    public static List<Event> removeNonSOAPEvents(List<Event> sequence) {
139        List<Event> soapOnlySequence = new LinkedList<>();
140        for (Event event : sequence) {
141            if (event.getType() instanceof SOAPEventType) {
142                soapOnlySequence.add(event);
143            }
144        }
145        return soapOnlySequence;
146    }
147
148    /**
149     * <p>
150     * Helper function to get the name of a service from a SOAP event.
151     * </p>
152     *
153     * @param event
154     *            event for which the service name is retrieved
155     * @return service name
156     */
157    public static String getServiceNameFromEvent(Event event) {
158        if (event.getType() instanceof SOAPEventType) {
159            return ((SOAPEventType) event.getType()).getServiceName();
160        }
161        else if (event.getType() instanceof SimpleSOAPEventType) {
162            return ((SimpleSOAPEventType) event.getType()).getServiceName();
163        }
164        else {
165            throw new RuntimeException(
166                                       "Wrong event type. Only SOAPEventType and SimpleSOAPEventType supported but was: " +
167                                           event.getType().getClass().getName());
168        }
169    }
170
171    /**
172     *
173     * <p>
174     * Helper function to get the called method from a SOAP event
175     * </p>
176     *
177     * @param event
178     *            event for which the called method is retrieved
179     * @return called method
180     */
181    public static String getCalledMethodFromEvent(Event event) {
182        if (event.getType() instanceof SOAPEventType) {
183            return ((SOAPEventType) event.getType()).getCalledMethod();
184        }
185        else if (event.getType() instanceof SimpleSOAPEventType) {
186            return ((SimpleSOAPEventType) event.getType()).getCalledMethod();
187        }
188        else {
189            throw new RuntimeException(
190                                       "Wrong event type. Only SOAPEventType and SimpleSOAPEventType supported but was: " +
191                                           event.getType().getClass().getName());
192        }
193    }
194
195    /**
196     * <p>
197     * Helper function to get the name of a client from a SOAP event.
198     * </p>
199     *
200     * @param event
201     *            event for which the client name is retrieved
202     * @return service name
203     */
204    public static String getClientNameFromEvent(Event event) {
205        if (event.getType() instanceof SOAPEventType) {
206            return ((SOAPEventType) event.getType()).getClientName();
207        }
208        else if (event.getType() instanceof SimpleSOAPEventType) {
209            return ((SimpleSOAPEventType) event.getType()).getClientName();
210        }
211        else {
212            throw new RuntimeException(
213                                       "Wrong event type. Only SOAPEventType and SimpleSOAPEventType supported but was: " +
214                                           event.getType().getClass().getName());
215        }
216    }
217
218    /**
219     * <p>
220     * Helper function to get the body of a SOAP request.
221     * </p>
222     *
223     * @param event
224     *            event for which the SOAP request body is retrieved
225     * @return body of the SOAP event
226     */
227    public static Element getSoapBodyFromEvent(Event event) {
228        return getSoapBodyFromEvent(event, false, CallType.REQUEST);
229    }
230
231    /**
232     * <p>
233     * Helper function to get the body of a SOAP message.
234     * </p>
235     *
236     * @param event
237     *            event for which the SOAP message body is retrieved
238     * @param useRandomBodies
239     *            defines if random message bodies are used or the body of the associated event
240     * @param callType
241     *            defines if the request or response of a message is retrieved
242     * @return body of the SOAP event
243     */
244    public static Element getSoapBodyFromEvent(Event event,
245                                               boolean useRandomBodies,
246                                               CallType callType)
247    {
248        if (event.getType() instanceof SOAPEventType) {
249            switch (callType)
250            {
251                case REQUEST:
252                    return ((SOAPEventType) event.getType()).getSoapRequestBody();
253                case RESPONSE:
254                    return ((SOAPEventType) event.getType()).getSoapResponseBody();
255                default:
256                    throw new RuntimeException("unsupported call type: " + callType);
257            }
258        }
259        else if (event.getType() instanceof SimpleSOAPEventType) {
260            switch (callType)
261            {
262                case REQUEST:
263                    if (((SimpleSOAPEventType) event.getType()).getCallType() == CallType.REQUEST) {
264                        if (useRandomBodies) {
265                            return ((SimpleSOAPEventType) event.getType()).getRandomSoapMsgBody();
266                        }
267                        else {
268                            return ((SimpleSOAPEventType) event.getType()).getSoapMsgBody();
269                        }
270                    }
271                    else {
272                        throw new RuntimeException(
273                                                   "cannot retrieve request body, is of CallType: " +
274                                                       ((SimpleSOAPEventType) event.getType())
275                                                           .getCallType());
276                    }
277                case RESPONSE:
278                    if (((SimpleSOAPEventType) event.getType()).getCallType() == CallType.RESPONSE)
279                    {
280                        if (useRandomBodies) {
281                            return ((SimpleSOAPEventType) event.getType()).getRandomSoapMsgBody();
282                        }
283                        else {
284                            return ((SimpleSOAPEventType) event.getType()).getSoapMsgBody();
285                        }
286                    }
287                    else {
288                        throw new RuntimeException(
289                                                   "cannot retrieve response body, is of CallType: " +
290                                                       ((SimpleSOAPEventType) event.getType())
291                                                           .getCallType());
292                    }
293                default:
294                    throw new RuntimeException("unsupported call type: " + callType);
295            }
296        }
297        else {
298            throw new RuntimeException(
299                                       "unsupported event type; must be SOAPEventType or SimpleSOAPEventType but is: " +
300                                           event.getType().getClass().getName());
301        }
302    }
303
304    /**
305     * <p>
306     * Checks if an event is a SOAP request
307     * </p>
308     *
309     * @param event
310     *            event that is checked
311     * @return true if SOAP request; false otherwise
312     */
313    public static boolean isSOAPRequest(Event event) {
314        if (event.getType() instanceof SOAPEventType) {
315            return true;
316        }
317        else if (event.getType() instanceof SimpleSOAPEventType) {
318            return ((SimpleSOAPEventType) event.getType()).getCallType() == CallType.REQUEST;
319        }
320        else {
321            throw new RuntimeException(
322                                       "unsupported event type; must be SOAPEventType or SimpleSOAPEventType but is: " +
323                                           event.getType().getClass().getName());
324        }
325    }
326
327    /**
328     * <p>
329     * Checks if an event is a SOAP response
330     * </p>
331     *
332     * @param event
333     *            event that is checked
334     * @return true if SOAP response; false otherwise
335     */
336    public static boolean isSOAPResponse(Event event) {
337        if (event.getType() instanceof SOAPEventType) {
338            return true;
339        }
340        else if (event.getType() instanceof SimpleSOAPEventType) {
341            return ((SimpleSOAPEventType) event.getType()).getCallType() == CallType.RESPONSE;
342        }
343        else {
344            throw new RuntimeException(
345                                       "unsupported event type; must be SOAPEventType or SimpleSOAPEventType but is: " +
346                                           event.getType().getClass().getName());
347        }
348    }
349
350    /**
351     * <p>
352     * returns the XML serialization of a DOM node; located here because it is used for SOAP request
353     * bodies
354     * </p>
355     *
356     * @param node
357     *            DOM node that is serialized
358     * @return XML serialization as String; null if node is null
359     */
360    public static String getSerialization(Node node) {
361        if (node == null) {
362            return null;
363        }
364        try {
365            StringWriter writer = new StringWriter();
366            Transformer transformer = TransformerFactory.newInstance().newTransformer();
367            transformer.transform(new DOMSource(node), new StreamResult(writer));
368            return writer.toString();
369        }
370        catch (TransformerFactoryConfigurationError | TransformerException e) {
371            throw new IllegalArgumentException(
372                                               "could not create serialization for SOAP request body.",
373                                               e);
374        }
375    }
376
377    /**
378     * <p>
379     * Fetches all {@link Element}s that are direct children of the parent node, whose name matches
380     * the given name.
381     * </p>
382     *
383     * @param typeNameRaw
384     *            name of elements that are looked for
385     * @param parentNode
386     *            DOM node in which the elements are searched for
387     * @return found {@link Element}s
388     */
389    public static List<Element> getMatchingChildNode(String typeNameRaw, Element parentNode) {
390        List<Element> matchingNodes = new ArrayList<>();
391        Node parameterNode = null;
392        if (parentNode != null) {
393            NodeList parameterNodes = parentNode.getChildNodes();
394            String[] typeNameSplit = typeNameRaw.split(":");
395            String typeName = typeNameSplit[typeNameSplit.length - 1];
396            for (int i = 0; i < parameterNodes.getLength(); i++) {
397                parameterNode = parameterNodes.item(i);
398                if (parameterNode.getNodeType() == Node.ELEMENT_NODE) {
399                    String[] parameterNodeSplit = parameterNode.getNodeName().split(":");
400                    String parameterNodeName = parameterNodeSplit[parameterNodeSplit.length - 1];
401                    if (typeName.equals(parameterNodeName)) {
402                        matchingNodes.add((Element) parameterNode);
403                    }
404                }
405            }
406        }
407        return matchingNodes;
408    }
409   
410    /**
411     * <p>
412     * Fetches the names of all child elements of a node
413     * </p>
414     *
415     * @param parentNode node for which the child names are fetched
416     * @return names of the child nodes
417     */
418    public static List<String> getChildNodeNames(Element parentNode) {
419        List<String> childNames = new LinkedList<>();
420        Node parameterNode = null;
421        if (parentNode != null) {
422            NodeList parameterNodes = parentNode.getChildNodes();
423            for (int i = 0; i < parameterNodes.getLength(); i++) {
424                parameterNode = parameterNodes.item(i);
425                if (parameterNode.getNodeType() == Node.ELEMENT_NODE) {
426                    String[] parameterNodeSplit = parameterNode.getNodeName().split(":");
427                    String parameterNodeName = parameterNodeSplit[parameterNodeSplit.length - 1];
428                    childNames.add(parameterNodeName);
429                }
430            }
431        }
432        return childNames;
433    }
434   
435    /**
436     * <p>
437     * Fetches all children of type {@link Element} from a parent node
438     * </p>
439     *
440     * @param parentNode node for which the child elements are fetched
441     * @return the child elements
442     */
443    public static List<Element> getChildElements(Element parentNode) {
444        List<Element> childElements = new LinkedList<>();
445        Node parameterNode = null;
446        if (parentNode != null) {
447            NodeList parameterNodes = parentNode.getChildNodes();
448            for (int i = 0; i < parameterNodes.getLength(); i++) {
449                parameterNode = parameterNodes.item(i);
450                if (parameterNode.getNodeType() == Node.ELEMENT_NODE) {
451                    childElements.add((Element) parameterNode);
452                }
453            }
454        }
455        return childElements;
456    }
457
458    /**
459     * <p>
460     * Returns the values found in a currentNode for a defined valueName. To this aim, this methods
461     * first determines if there is an attribute with the name "valueName". If this is the case, the
462     * value of this attribute is returned. Otherwise, the methods looks for {@link Element}s that
463     * are direct children of the provided DOM node with the given name and returns the text content
464     * of those nodes.
465     * </p>
466     * <p>
467     * In case no values can be found, an empty list is returned
468     *
469     * @param valueName
470     *            name of the value that is retrieved
471     * @param node
472     *            node for which the value is retrieved
473     * @return list of the found values.
474     */
475    public static List<String> getValuesFromElement(String valueName, Element node) {
476        List<String> attributeValues = new LinkedList<>();
477
478        if (node != null) {
479            // first check attributes of the node
480            Attr attribute = node.getAttributeNode(valueName);
481            if (attribute != null) {
482                attributeValues.add(attribute.getValue());
483            }
484            else {
485                // now check elements
486                List<Element> elements = getMatchingChildNode(valueName, node);
487                for (Element element : elements) {
488                    attributeValues.add(element.getTextContent());
489                }
490            }
491        }
492
493        return attributeValues;
494    }
495
496    /**
497     * <p>
498     * Allows the removal of pre- and suffixes from SOAP operation names in
499     * {@link SimpleSOAPEventType}.
500     * </p>
501     *
502     * @param sequences
503     *            sequences where the operation names are normalized
504     */
505    public static Collection<List<Event>> normalizeOperationNames(Collection<List<Event>> sequences,
506                                                                  String prefixToRemove,
507                                                                  String suffixToRemove)
508    {
509        Collection<List<Event>> normalizedSequences = new LinkedList<>();
510        for (List<Event> sequence : sequences) {
511            List<Event> normalizedSequence = new LinkedList<>();
512            for (Iterator<Event> eventIter = sequence.iterator(); eventIter.hasNext();) {
513                Event event = eventIter.next();
514                if ((event.getType() instanceof SimpleSOAPEventType)) {
515                    SimpleSOAPEventType eventType = (SimpleSOAPEventType) event.getType();
516                    String methodName = eventType.getCalledMethod();
517                    if (prefixToRemove != null && methodName.startsWith(prefixToRemove)) {
518                        methodName =
519                            methodName.substring(prefixToRemove.length(), methodName.length());
520                        // remove prefix
521                    }
522                    if (suffixToRemove != null && methodName.endsWith(suffixToRemove)) {
523                        methodName =
524                            methodName.substring(0, methodName.length() - suffixToRemove.length());
525                    }
526                    event =
527                        new Event(new SimpleSOAPEventType(methodName, eventType.getServiceName(),
528                                                          eventType.getClientName(),
529                                                          eventType.getSoapMsgBody(),
530                                                          eventType.getEqualSOAPDataMap(),
531                                                          eventType.getCallType()),
532                                  event.getTarget());
533                }
534                normalizedSequence.add(event);
535            }
536            normalizedSequences.add(normalizedSequence);
537        }
538        return normalizedSequences;
539    }
540
541    /**
542     * <p>
543     * Sorts the sequences by the orderingId of the requests/responses. This function only supports
544     * the ordering of {@link Event}s with a {@link SOAPEventType}.
545     * </p>
546     *
547     * @param sequences
548     *            sequences to be order
549     * @param orderType
550     *            determines if sequences are ordered by request or response
551     * @return sorted sequences
552     */
553    public static Collection<List<Event>> sortSequences(Collection<List<Event>> sequences,
554                                                        SequenceOrder orderType)
555    {
556        Collection<List<Event>> sortedSequences = new LinkedList<>();
557        for (List<Event> sequence : sequences) {
558            // use insertion sort
559            List<Event> sortedSequence = new LinkedList<>();
560            long lastOrderId = Long.MIN_VALUE;
561            long selectedOrderId;
562            Event selectedEvent;
563            while (sortedSequence.size() != sequence.size()) {
564                selectedEvent = null;
565                selectedOrderId = Long.MAX_VALUE;
566                for (Event event : sequence) {
567                    if (!(event.getType() instanceof SOAPEventType)) {
568                        throw new RuntimeException(
569                                                   "Can only order SOAPEventTypes. SimpleSOAPEvent is also not supported. Event type found: " +
570                                                       event.getType().getClass().getName());
571                    }
572                    SOAPEventType soapEventType = (SOAPEventType) event.getType();
573                    long eventOrderId;
574                    switch (orderType)
575                    {
576                        case REQUEST:
577                            eventOrderId = soapEventType.getExchange().getRequest().getOrderingId();
578                            break;
579                        case RESPONSE:
580                            eventOrderId =
581                                soapEventType.getExchange().getResponse().getOrderingId();
582                            break;
583                        default:
584                            throw new RuntimeException("unsupported order type: " +
585                                orderType.toString());
586                    }
587                    if (eventOrderId > lastOrderId && eventOrderId < selectedOrderId) {
588                        selectedOrderId = eventOrderId;
589                        selectedEvent = event;
590                    }
591                }
592                if (selectedEvent != null) {
593                    sortedSequence.add(selectedEvent);
594                    lastOrderId = selectedOrderId;
595                }
596                else {
597                    throw new RuntimeException(
598                                               "could not select next event; possibly the same order Id for multiple exchanges events!?");
599                }
600            }
601            sortedSequences.add(sortedSequence);
602        }
603        return sortedSequences;
604    }
605
606    /**
607     * <p>
608     * Sorts the sequences by the orderingId of the requests/responses. This function only supports
609     * the ordering of {@link Event}s with a {@link SOAPEventType}.
610     * </p>
611     *
612     * @param sequences
613     *            sequences to be order
614     * @param orderType
615     *            determines if sequences are ordered by request or response
616     * @return sorted sequences
617     */
618    public static Collection<List<Event>> sortAndConvertSequences(Collection<List<Event>> sequences,
619                                                                  boolean keepRequests,
620                                                                  boolean keepResponse)
621    {
622        Collection<List<Event>> sortedSequences = new LinkedList<>();
623        EqualSOAPDataMap equalSOAPDataMap = new EqualSOAPDataMap();
624        for (List<Event> sequence : sequences) {
625            // use insertion sort
626            List<Event> sortedSequence = new LinkedList<>();
627            long lastOrderId = Long.MIN_VALUE;
628            long selectedOrderId;
629            Event selectedEvent;
630            CallType selectedCallType = CallType.RESPONSE;
631            do {
632                selectedEvent = null;
633                selectedOrderId = Long.MAX_VALUE;
634                for (Event event : sequence) {
635                    if (!(event.getType() instanceof SOAPEventType)) {
636                        throw new RuntimeException(
637                                                   "Can only order SOAPEventTypes. SimpleSOAPEvent is also not supported. Event type found: " +
638                                                       event.getType().getClass().getName());
639                    }
640                    SOAPEventType soapEventType = (SOAPEventType) event.getType();
641                    long requestOrderId = soapEventType.getExchange().getRequest().getOrderingId();
642                    long responseOrderId =
643                        soapEventType.getExchange().getResponse().getOrderingId();
644                    // System.out.println(requestOrderId + " / " + responseOrderId);
645
646                    if (requestOrderId > lastOrderId && requestOrderId < selectedOrderId) {
647                        selectedOrderId = requestOrderId;
648                        selectedEvent = event;
649                        selectedCallType = CallType.REQUEST;
650                    }
651                    if (responseOrderId > lastOrderId && responseOrderId < selectedOrderId) {
652                        selectedOrderId = responseOrderId;
653                        selectedEvent = event;
654                        selectedCallType = CallType.RESPONSE;
655                    }
656                }
657                if (selectedEvent != null) {
658                    SOAPEventType eventType = (SOAPEventType) selectedEvent.getType();
659                    Element soapMsgBody;
660                    switch (selectedCallType)
661                    {
662                        case REQUEST:
663                            soapMsgBody = eventType.getSoapRequestBody();
664                            break;
665                        case RESPONSE:
666                            soapMsgBody = eventType.getSoapResponseBody();
667                            break;
668                        default:
669                            throw new RuntimeException("unsupported call type: " + selectedCallType);
670                    }
671                    if ((keepRequests && selectedCallType == CallType.REQUEST) ||
672                        (keepResponse && selectedCallType == CallType.RESPONSE))
673                    {
674                        sortedSequence.add(new Event(new SimpleSOAPEventType(eventType
675                            .getCalledMethod(), eventType.getServiceName(), eventType
676                            .getClientName(), soapMsgBody, equalSOAPDataMap, selectedCallType)));
677                    }
678                    lastOrderId = selectedOrderId;
679                }
680
681            }
682            while (selectedEvent != null);
683            sortedSequences.add(sortedSequence);
684        }
685        return sortedSequences;
686    }
687
688    /**
689     * <p>
690     * Removes calls to and from all ignored services from the sequences.
691     * </p>
692     *
693     * @param sequences
694     *            sequences where the ignored services are removed
695     * @param ignoredServicesString
696     *            comma separted string that defines the ignored services
697     * @return sequences without events that reference the ignored services
698     */
699    public static Collection<List<Event>> removeCallsToIgnoredServices(Collection<List<Event>> sequences,
700                                                                       String ignoredServicesString)
701    {
702        Set<String> ignoredServices = new HashSet<>();
703        if (ignoredServicesString != null) {
704            for (String service : ignoredServicesString.split(",")) {
705                ignoredServices.add(service.trim());
706            }
707        }
708        return removeCallsToIgnoredServices(sequences, ignoredServices);
709    }
710
711    /**
712     * <p>
713     * Removes calls to and from all ignored services from the sequences.
714     * </p>
715     *
716     * @param sequences
717     *            sequences where the ignored services are removed
718     * @param ignoredServices
719     *            set with all ignored service names
720     * @return sequences without events that reference the ignored services
721     */
722    public static Collection<List<Event>> removeCallsToIgnoredServices(Collection<List<Event>> sequences,
723                                                                       Set<String> ignoredServices)
724    {
725        Collection<List<Event>> onlyAcceptedServicesSequences = new LinkedList<>();
726        for (List<Event> sequence : sequences) {
727            List<Event> onlyAcceptedServicesSequence = new LinkedList<>();
728            for (Event event : sequence) {
729                SimpleSOAPEventType eventType = (SimpleSOAPEventType) event.getType();
730                if (!ignoredServices.contains(eventType.getServiceName()) &&
731                    !ignoredServices.contains(eventType.getClientName()))
732                {
733                    onlyAcceptedServicesSequence.add(event);
734                }
735            }
736            onlyAcceptedServicesSequences.add(onlyAcceptedServicesSequence);
737        }
738        return onlyAcceptedServicesSequences;
739    }
740
741    /**
742     * <p>
743     * Drops all requests without responses as well as invalid request/response orders. Only the
744     * part of the sequence before the first invalid occurrence is kept.
745     * </p>
746     *
747     * @param sequences
748     *            sequences where the invalid pairs are dropped
749     * @return sequences with only valid and complete interactions
750     */
751    public static Collection<List<Event>> dropInvalidResponseRequestPairs(Collection<List<Event>> sequences)
752    {
753        Collection<List<Event>> validSequences = new LinkedList<>();
754        int i = 0;
755        for (List<Event> sequence : sequences) {
756            List<Event> validSequence = dropInvalidResponseRequestPairs(sequence);
757            if (validSequence.isEmpty() ||
758                (validSequence.size() <= 2 && validSequence.get(0) == Event.STARTEVENT))
759            {
760                Console.traceln(Level.INFO, "dropped sequence " + i +
761                    ": empty after removal of invalid request/response pairs");
762            }
763            validSequences.add(validSequence);
764            i++;
765        }
766        return validSequences;
767    }
768
769    /**
770     * <p>
771     * Drops all requests without responses as well as invalid request/response orders. Only the
772     * part of the sequence before the first invalid occurrence is kept.
773     * </p>
774     *
775     * @param sequence
776     *            sequence where the invalid pairs are dropped
777     * @return sequence with only valid and complete interactions
778     */
779    public static List<Event> dropInvalidResponseRequestPairs(List<Event> sequence) {
780        Stack<SimpleSOAPEventType> unrespondedRequests = new Stack<>();
781        boolean hasStartEvent = false;
782        int lastValidIndex = 0;
783        int i = 0;
784        for (Event event : sequence) {
785            if (event == Event.STARTEVENT) {
786                hasStartEvent = true;
787                lastValidIndex = i;
788            }
789            else if (event.getType() instanceof SimpleSOAPEventType) {
790                SimpleSOAPEventType currentEventType = (SimpleSOAPEventType) event.getType();
791                if (SOAPUtils.isSOAPRequest(event)) {
792                    unrespondedRequests.push(currentEventType);
793                }
794                else if (SOAPUtils.isSOAPResponse(event)) {
795                    if (unrespondedRequests.empty()) {
796                        break; // found a response without previous request; sequence invalid from
797                               // here
798                    }
799                    else {
800                        SimpleSOAPEventType lastRequest = unrespondedRequests.peek();
801                        if (isRequestResponseMatch(lastRequest, currentEventType)) {
802                            unrespondedRequests.pop();
803                            if (unrespondedRequests.empty()) {
804                                lastValidIndex = i;
805                            }
806                        }
807                    }
808
809                }
810            }
811            i++;
812        }
813        List<Event> validSequence = new LinkedList<>(sequence.subList(0, lastValidIndex + 1));
814        if (hasStartEvent) {
815            validSequence.add(Event.ENDEVENT);
816        }
817        return validSequence;
818    }
819
820    /**
821     * <p>
822     * Checks if two {@link SimpleSOAPEventType} types are equal except their {@link CallType},
823     * which must be {@value CallType#REQUEST} for the first parameter and {@link CallType#RESPONSE}
824     * for the second parameter.
825     * </p>
826     *
827     * @param request
828     *            request soap event
829     * @param response
830     *            response soap event
831     * @return true if they are a matching request/response pair
832     */
833    public static boolean isRequestResponseMatch(SimpleSOAPEventType request,
834                                                 SimpleSOAPEventType response)
835    {
836        if (request == null && response == null) {
837            return true;
838        }
839        if ((request != null && response == null) || (request == null && response != null)) {
840            return false;
841        }
842        return request.getCallType().equals(CallType.REQUEST) &&
843            response.getCallType().equals(CallType.RESPONSE) &&
844            HTTPUtils.equals(request.getCalledMethod(), response.getCalledMethod()) &&
845            HTTPUtils.equals(request.getServiceName(), response.getServiceName()) &&
846            HTTPUtils.equals(request.getClientName(), response.getClientName());
847    }
848
849    /**
850     * <p>
851     * prevent instantiation
852     * </p>
853     */
854    private SOAPUtils() {}
855}
Note: See TracBrowser for help on using the repository browser.