source: trunk/autoquest-plugin-mfc/src/main/java/de/ugoe/cs/autoquest/plugin/mfc/EventGenerationRule.java @ 927

Last change on this file since 927 was 927, checked in by sherbold, 12 years ago
  • added copyright under the Apache License, Version 2.0
File size: 25.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.mfc;
16
17import java.util.ArrayList;
18import java.util.List;
19
20import org.jdom.Element;
21import org.jdom.Namespace;
22
23import de.ugoe.cs.autoquest.plugin.mfc.eventcore.WindowsMessageType;
24
25/**
26 * <p>
27 * This class defines rules for the generation of MFC events.
28 * </p>
29 *
30 * @version 1.0
31 * @author Steffen Herbold, Patrick Harms
32 */
33class EventGenerationRule {
34
35    /**
36     * <p>
37     * Namespace used for parsing the rule.
38     * </p>
39     */
40    private Namespace namespace;
41
42    /**
43     * <p>
44     * Name of the rule.
45     * </p>
46     */
47    private String name;
48
49    /**
50     * <p>
51     * List of conditions for the rule to be matched.
52     * </p>
53     */
54    private List<MessageCondition> messageConditions;
55
56    /**
57     * <p>
58     * List of parameters to be provided to the generated event.
59     * </p>
60     */
61    private List<Term> eventParameters;
62
63    /**
64     * <p>
65     * List of replay message generation rules.
66     * </p>
67     */
68    private List<ReplayMessageSpec> replayMessageSpecifications;
69
70    /**
71     * <p>
72     * Constructor. Creates a new EventGenerationRule.
73     * </p>
74     *
75     * @param ruleElement
76     *            the JDOM element that descripes the rule
77     * @param rulesNamespace
78     *            the XML namespace the rule is defined in
79     */
80    @SuppressWarnings("unchecked")
81    EventGenerationRule(Element ruleElement, Namespace rulesNamespace) {
82        this.namespace = rulesNamespace;
83
84        this.name = ruleElement.getAttributeValue("name");
85
86        this.messageConditions = new ArrayList<MessageCondition>();
87        this.eventParameters = new ArrayList<Term>();
88        this.replayMessageSpecifications = new ArrayList<ReplayMessageSpec>();
89
90        for (Element child : (List<Element>) ruleElement.getChildren()) {
91            if ("msg".equals(child.getName()) && namespace.equals(child.getNamespace())) {
92                messageConditions.add(new MessageCondition(child));
93            }
94            else if ("idinfo".equals(child.getName()) && namespace.equals(child.getNamespace())) {
95                for (Element parameterElements : (List<Element>) child.getChildren()) {
96                    eventParameters.add(new Term(parameterElements));
97                }
98            }
99            else if ("genMsg".equals(child.getName()) && namespace.equals(child.getNamespace())) {
100                replayMessageSpecifications.add(new ReplayMessageSpec(child));
101            }
102            else if ("genMsgSeq".equals(child.getName()) && namespace.equals(child.getNamespace()))
103            {
104                replayMessageSpecifications.add(new ReplayMessageSpec(child));
105            }
106            else {
107                throw new IllegalArgumentException(
108                                                   "the provided rules can not be parsed: unknown element " +
109                                                       child.getName());
110            }
111        }
112    }
113
114    /**
115     * <p>
116     * Returns the name of the rule.
117     * </p>
118     *
119     * @return the name
120     */
121    String getName() {
122        return name;
123    }
124
125    /**
126     * <p>
127     * Returns the conditions on the matched messages defined by this rule.
128     * </p>
129     *
130     * @return the message conditions
131     */
132    List<MessageCondition> getMessageConditions() {
133        return messageConditions;
134    }
135
136    /**
137     * <p>
138     * Returns the parameters of the event generated by this rule.
139     * </p>
140     *
141     * @return the event parameters
142     */
143    List<Term> getEventParameters() {
144        return eventParameters;
145    }
146
147    /**
148     * <p>
149     * Returns the replay specification defined by this rule.
150     * </p>
151     *
152     * @return the replay specification
153     */
154    List<ReplayMessageSpec> getReplayMessageSpecifications() {
155        return replayMessageSpecifications;
156    }
157
158    /**
159     * <p>
160     * Helper class that describes conditions on the message sequence when matching this rule.
161     * </p>
162     *
163     * @version 1.0
164     * @author Steffen Herbold, Patrick Harms
165     */
166    class MessageCondition {
167
168        /**
169         * <p>
170         * True, if the condition defines to match several conditions
171         * </p>
172         */
173        private boolean matchMultiple;
174
175        /**
176         * <p>
177         * Type of the message matched by the condition
178         * </p>
179         */
180        private WindowsMessageType messageType;
181
182        /**
183         * <p>
184         * Term conditions associated with the rule condition
185         * </p>
186         */
187        private List<AttributeCondition> attributeConditions;
188
189        /**
190         * <p>
191         * List of messages to be stored, if the message matches, for continuing the rule
192         * application
193         * </p>
194         */
195        private ArrayList<Term> messagesToStore;
196
197        /**
198         * <p>
199         * Constructor. Creates a new MessageCondition.
200         * </p>
201         *
202         * @param msgChild
203         *            JDOM element that describes the message condition
204         */
205        @SuppressWarnings("unchecked")
206        private MessageCondition(Element msgChild) {
207            this.matchMultiple = "true".equals(msgChild.getAttributeValue("multiple"));
208            this.messageType =
209                WindowsMessageType.parseMessageType(msgChild.getAttributeValue("type"));
210
211            this.attributeConditions = new ArrayList<AttributeCondition>();
212            for (Element childElement : (List<Element>) msgChild.getChildren("equals", namespace)) {
213                attributeConditions.add(new AttributeCondition(childElement));
214            }
215
216            this.messagesToStore = new ArrayList<Term>();
217            for (Element childElement : (List<Element>) msgChild.getChildren("store", namespace)) {
218                messagesToStore.add(new Term(childElement));
219            }
220            for (Element childElement : (List<Element>) msgChild.getChildren("storeSeq", namespace))
221            {
222                messagesToStore.add(new Term(childElement));
223            }
224        }
225
226        /**
227         * <p>
228         * Returns whether a single message is matched to the condition or a whole sequence can be
229         * matched.
230         * </p>
231         *
232         * @return true if multiple message shall be matched, false if only a single message is
233         *         matched
234         */
235        boolean matchMultiple() {
236            return matchMultiple;
237        }
238
239        /**
240         * <p>
241         * Returns the type of the matched messages.
242         * </p>
243         *
244         * @return the message type
245         */
246        WindowsMessageType getMessageType() {
247            return messageType;
248        }
249
250        /**
251         * <p>
252         * Returns the attribute conditions of the message condition.
253         * </p>
254         *
255         * @return the attribute conditions
256         */
257        List<AttributeCondition> getAttributeConditions() {
258            return attributeConditions;
259        }
260
261        /**
262         * <p>
263         * Returns messages, that have eventually been stored as part of the condition.
264         * </p>
265         *
266         * @return the stored messages
267         */
268        ArrayList<Term> getMessagesToStore() {
269            return messagesToStore;
270        }
271
272    }
273
274    /**
275     * <p>
276     * Helper class that defines attribute conditions for matching messages.
277     * </p>
278     *
279     * @version 1.0
280     * @author Steffen Herbold, Patrick Harms
281     */
282    class AttributeCondition {
283
284        /**
285         * <p>
286         * Left hand side of the condition.
287         * </p>
288         */
289        private Term leftHandSide;
290
291        /**
292         * <p>
293         * Reft hand side of the condition.
294         * </p>
295         */
296        private Term rightHandSide;
297
298        /**
299         * <p>
300         * Constructor. Creates a new AttributeCondition.
301         * </p>
302         *
303         * @param conditionElement
304         *            JDOM element that describes the condition
305         */
306        private AttributeCondition(Element conditionElement) {
307            this.leftHandSide = new Term((Element) conditionElement.getChildren().get(0));
308            this.rightHandSide = new Term((Element) conditionElement.getChildren().get(1));
309        }
310
311        /**
312         * <p>
313         * Returns the left hand side of the condition.
314         * </p>
315         *
316         * @return the left hand side
317         */
318        Term getLeftHandSide() {
319            return leftHandSide;
320        }
321
322        /**
323         * <p>
324         * Returns the right hand side of the condition.
325         * </p>
326         *
327         * @return the right hand side
328         */
329        Term getRightHandSide() {
330            return rightHandSide;
331        }
332
333    }
334
335    /**
336     * <p>
337     * Helper class that defines terms to define conditions.
338     * </p>
339     *
340     * @version 1.0
341     * @author Steffen Herbold, Patrick Harms
342     */
343    class Term {
344
345        /**
346         * <p>
347         * Name of the term.
348         * </p>
349         */
350        private String name;
351
352        /**
353         * <p>
354         * Value of the term, if it is a constValue; null otherwise.
355         * </p>
356         */
357        private String value;
358
359        /**
360         * <p>
361         * Variable name of the object, i.e. a message, of which a parameter is identified if the
362         * term is a winInfoValue or a msgInfoValue; null otherwise.
363         * </p>
364         */
365        private String messageId;
366
367        /**
368         * <p>
369         * Name of the parameter of the object, i.e., a message, of which a parameter is identified
370         * if the term is a paramValue; null otherwise.
371         * </p>
372         */
373        private String messageParameterName;
374
375        /**
376         * <p>
377         * Variable name of the message sequence denoted by the term in case of a seqValue; null
378         * otherwise.
379         * </p>
380         */
381        private String sequenceId;
382
383        /**
384         * <p>
385         * Name of the parameter of the sequence of which a parameter is identified if the term is a
386         * seqValue; null otherwise.
387         * </p>
388         */
389        private String sequenceParameterName;
390
391        /**
392         * <p>
393         * Name of the parameter of the window of the object, e.g. a message, of which a parameter
394         * is identified if the term is a winInfoValue; null otherwise.
395         * </p>
396         */
397        private String windowParameterName;
398
399        /**
400         * <p>
401         * Name of the info of the message of which a parameter is identified if the term is a
402         * msgInfoValue; null otherwise.
403         * </p>
404         */
405        private String messageInfoName;
406
407        /**
408         * <p>
409         * Name of the parameter of the message into which a value shall be stored if the term is a
410         * resolveHwnd, null otherwise
411         * </p>
412         */
413        private String storeParameterName;
414
415        /**
416         * <p>
417         * List of handles to be resolved in case the term is a store or storeSeq; null otherwise.
418         * </p>
419         */
420        private List<Term> resolveHandles;
421
422        /**
423         * <p>
424         * Constructor. Creates a new Term.
425         * </p>
426         *
427         * @param termElement
428         *            JDOM element that describes the term
429         */
430        @SuppressWarnings("unchecked")
431        private Term(Element termElement) {
432            this.name = termElement.getName();
433
434            if ("constValue".equals(name)) {
435                this.value = termElement.getAttributeValue("value");
436            }
437            else if ("paramValue".equals(name)) {
438                this.messageId = termElement.getAttributeValue("obj");
439                this.messageParameterName = termElement.getAttributeValue("param");
440            }
441            else if ("winInfoValue".equals(name)) {
442                this.messageId = termElement.getAttributeValue("obj");
443                this.windowParameterName = termElement.getAttributeValue("winParam");
444            }
445            else if ("msgInfoValue".equals(name)) {
446                this.messageId = termElement.getAttributeValue("obj");
447                this.messageInfoName = termElement.getAttributeValue("msgParam");
448            }
449            else if ("seqValue".equals(name)) {
450                this.sequenceId = termElement.getAttributeValue("seqObj");
451                this.sequenceParameterName = termElement.getAttributeValue("param");
452            }
453            else if ("store".equals(name)) {
454                this.messageId = termElement.getAttributeValue("var");
455                if ((termElement.getChildren() != null) && (termElement.getChildren().size() > 0)) {
456                    this.resolveHandles = new ArrayList<Term>();
457                    for (Element child : (List<Element>) termElement.getChildren()) {
458                        this.resolveHandles.add(new Term(child));
459                    }
460                }
461            }
462            else if ("storeSeq".equals(name)) {
463                this.sequenceId = termElement.getAttributeValue("varSeq");
464                if ((termElement.getChildren() != null) && (termElement.getChildren().size() > 0)) {
465                    this.resolveHandles = new ArrayList<Term>();
466                    for (Element child : (List<Element>) termElement.getChildren()) {
467                        this.resolveHandles.add(new Term(child));
468                    }
469                }
470            }
471            else if ("resolveHwnd".equals(name)) {
472                this.messageParameterName = termElement.getAttributeValue("param");
473                this.storeParameterName = termElement.getAttributeValue("storeParam");
474            }
475        }
476
477        /**
478         * <p>
479         * Returns the name of the term.
480         * </p>
481         *
482         * @return the name
483         */
484        String getName() {
485            return name;
486        }
487
488        /**
489         * <p>
490         * Returns the value of the term.
491         * </p>
492         *
493         * @return the value
494         */
495        String getValue() {
496            return value;
497        }
498
499        /**
500         * <p>
501         * Returns the object Id of the message, which is resolved as part of this term.
502         * </p>
503         *
504         * @return the object Id
505         */
506        String getMessageId() {
507            return messageId;
508        }
509
510        /**
511         * <p>
512         * Returns the name of the message parameter that is resolved as part of this term.
513         * </p>
514         *
515         * @return the message parameter name
516         */
517        String getMessageParameterName() {
518            return messageParameterName;
519        }
520
521        /**
522         * <p>
523         * Returns the object Id of the message sequence, which is resolved as part of this term.
524         * </p>
525         *
526         * @return the object Id
527         */
528        String getSequenceId() {
529            return sequenceId;
530        }
531
532        /**
533         * <p>
534         * Returns the name of the message parameter that is resolved as part of this term.
535         * </p>
536         *
537         * @return the sequenceParameter
538         */
539        String getSequenceParameterName() {
540            return sequenceParameterName;
541        }
542
543        /**
544         * <p>
545         * Returns the window parameter name that is resolved as part of this term.
546         * </p>
547         *
548         * @return the name of the window parameter
549         */
550        String getWindowParameterName() {
551            return windowParameterName;
552        }
553
554        /**
555         * <p>
556         * Returns the name of the message info value that is resolved as part of this term.
557         * </p>
558         *
559         * @return the name of the message info value
560         */
561        String getMessageInfoName() {
562            return messageInfoName;
563        }
564
565        /**
566         * <p>
567         * Returns the object Id under which a message will be stored.
568         * </p>
569         *
570         * @return the object Id
571         */
572        String getStoreParameterName() {
573            return storeParameterName;
574        }
575
576        /**
577         * <p>
578         * Returns all terms that are responsible to resolve HWNDs.
579         * </p>
580         *
581         * @return the terms
582         */
583        List<Term> getResolveHandles() {
584            return resolveHandles;
585        }
586
587    }
588
589    /**
590     * <p>
591     * Helper class that defines the replay specification part of rules.
592     * </p>
593     *
594     * @version 1.0
595     * @author Steffen Herbold, Patrick Harms
596     */
597    class ReplayMessageSpec {
598
599        /**
600         * <p>
601         * Determines if this specification defines one, or a sequence of messages.
602         * </p>
603         */
604        private boolean generateSingleMessage;
605
606        /**
607         * <p>
608         * Object Id of a concrete message of message sequence to be replayed as is.
609         * </p>
610         */
611        private String replayObjectId;
612
613        /**
614         * <p>
615         * Term describing the type of the generated message.
616         * </p>
617         */
618        private Term type;
619
620        /**
621         * <p>
622         * Term describing the target of the generated message.
623         * </p>
624         */
625        private Term target;
626
627        /**
628         * <p>
629         * Term describing the LO word of the LParam of the generated message.
630         * </p>
631         */
632        private Term lparamLoWord;
633
634        /**
635         * <p>
636         * Term describing the HI word of the LParam of the generated message.
637         * </p>
638         */
639        private Term lparamHiWord;
640
641        /**
642         * <p>
643         * Term describing the LParam of the generated message.
644         * </p>
645         */
646        private Term lparam;
647
648        /**
649         * <p>
650         * Term describing the LO word of the WParam of the generated message.
651         * </p>
652         */
653        private Term wparamLoWord;
654
655        /**
656         * <p>
657         * Term describing the HI word of the WParam of the generated message.
658         * </p>
659         */
660        private Term wparamHiWord;
661
662        /**
663         * <p>
664         * Term describing the WParam of the generated message.
665         * </p>
666         */
667        private Term wparam;
668
669        /**
670         * <p>
671         * Value in milliseconds that the replay waits until the the next message is replayed.
672         * </p>
673         */
674        private int delay;
675
676        /**
677         * <p>
678         * Constructor. Creates a new ReplayMessageSpec.
679         * </p>
680         *
681         * @param replayMessageSpecElement
682         *            JDOM element that describes the replay message specification
683         */
684        @SuppressWarnings("unchecked")
685        private ReplayMessageSpec(Element replayMessageSpecElement) {
686            List<Element> children = replayMessageSpecElement.getChildren();
687            if ("genMsg".equals(replayMessageSpecElement.getName())) {
688                generateSingleMessage = true;
689                if (children.size() == 1) {
690                    replayObjectId = children.get(0).getAttributeValue("obj");
691                }
692            }
693            else {
694                generateSingleMessage = false;
695                if (children.size() == 1) {
696                    replayObjectId = children.get(0).getAttributeValue("seqObj");
697                }
698            }
699
700            this.delay = Integer.parseInt(replayMessageSpecElement.getAttributeValue("delay"));
701
702            if (children.size() > 1) {
703                for (Element child : children) {
704                    Element termElement = (Element) child.getChildren().get(0);
705
706                    if (child.getName().equals("type")) {
707                        this.type = new Term(termElement);
708                    }
709                    else if (child.getName().equals("target")) {
710                        this.target = new Term(termElement);
711
712                        if (!generateSingleMessage) {
713                            // in this case, the target is always a sequence value term, i.e.
714                            // the targets of the originally recorded sequence. So the
715                            // replay object id is set to this sequence
716                            replayObjectId = target.getSequenceId();
717                        }
718                    }
719                    else if (child.getName().equals("LPARAM")) {
720                        Element loWordElement = child.getChild("LOWORD", namespace);
721                        if (loWordElement != null) {
722                            this.lparamLoWord =
723                                new Term((Element) loWordElement.getChildren().get(0));
724                        }
725
726                        Element hiWordElement = child.getChild("HIWORD", namespace);
727                        if (hiWordElement != null) {
728                            this.lparamHiWord =
729                                new Term((Element) hiWordElement.getChildren().get(0));
730                        }
731
732                        if ((lparamLoWord == null) && (lparamHiWord == null)) {
733                            this.lparam = new Term(termElement);
734                        }
735                    }
736                    else if (child.getName().equals("WPARAM")) {
737                        Element loWordElement = child.getChild("LOWORD", namespace);
738                        if (loWordElement != null) {
739                            this.wparamLoWord =
740                                new Term((Element) loWordElement.getChildren().get(0));
741                        }
742
743                        Element hiWordElement = child.getChild("HIWORD", namespace);
744                        if (hiWordElement != null) {
745                            this.wparamHiWord =
746                                new Term((Element) hiWordElement.getChildren().get(0));
747                        }
748
749                        if ((wparamLoWord == null) && (wparamHiWord == null)) {
750                            this.wparam = new Term(termElement);
751                        }
752                    }
753                }
754            }
755        }
756
757        /**
758         * <p>
759         * Determines if this specification defines one, or a sequence of messages.
760         * </p>
761         *
762         * @return true if only a single message is generated; false if a sequence is generated
763         */
764        boolean generateSingleMessage() {
765            return generateSingleMessage;
766        }
767
768        /**
769         * <p>
770         * Returns the object Id from which the message is generated.
771         * </p>
772         *
773         * @return the object Id
774         */
775        String getReplayObjectId() {
776            return replayObjectId;
777        }
778
779        /**
780         * <p>
781         * Returns the term that describes the type of the generated message.
782         * </p>
783         *
784         * @return the type term
785         */
786        Term getType() {
787            return type;
788        }
789
790        /**
791         * <p>
792         * Returns the term that describes the target of the generated message.
793         * </p>
794         *
795         * @return the target term
796         */
797        Term getTarget() {
798            return target;
799        }
800
801        /**
802         * <p>
803         * Returns the term that describes the LO word of the LParam of the generated message.
804         * </p>
805         *
806         * @return the LParam LO word term
807         */
808        Term getLparamLoWord() {
809            return lparamLoWord;
810        }
811
812        /**
813         * <p>
814         * Returns the term that describes the HI word of the LParam of the generated message.
815         * </p>
816         *
817         * @return the LParam HI word term
818         */
819        Term getLparamHiWord() {
820            return lparamHiWord;
821        }
822
823        /**
824         * <p>
825         * Returns the term that describes the LParam of the generated message.
826         * </p>
827         *
828         * @return the LParam term
829         */
830        Term getLparam() {
831            return lparam;
832        }
833
834        /**
835         * <p>
836         * Returns the term that describes the LO word of the WParam of the generated message.
837         * </p>
838         *
839         * @return the WParam LO word term
840         */
841        Term getWparamLoWord() {
842            return wparamLoWord;
843        }
844
845        /**
846         * <p>
847         * Returns the term that describes the HI word of the WParam of the generated message.
848         * </p>
849         *
850         * @return the WParam HI word term
851         */
852        Term getWparamHiWord() {
853            return wparamHiWord;
854        }
855
856        /**
857         * <p>
858         * Returns the term that describes the WParam of the generated message.
859         * </p>
860         *
861         * @return the WParam term
862         */
863        Term getWparam() {
864            return wparam;
865        }
866
867        /**
868         * <p>
869         * Returns the delay during the replay after this message is sent.
870         * </p>
871         *
872         * @return the delay
873         */
874        int getDelay() {
875            return delay;
876        }
877
878    }
879}
Note: See TracBrowser for help on using the repository browser.