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

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