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

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