package de.ugoe.cs.quest.plugin.mfc; import java.util.ArrayList; import java.util.List; import org.jdom.Element; import org.jdom.Namespace; import de.ugoe.cs.quest.plugin.mfc.eventcore.WindowsMessageType; /** *

* This class defines rules for the generation of MFC events. *

* * @version 1.0 * @author Steffen Herbold, Patrick Harms */ class EventGenerationRule { /** *

* Namespace used for parsing the rule. *

*/ private Namespace namespace; /** *

* Name of the rule. *

*/ private String name; /** *

* List of conditions for the rule to be matched. *

*/ private List messageConditions; /** *

* List of parameters to be provided to the generated event. *

*/ private List eventParameters; /** *

* List of replay message generation rules. *

*/ private List replayMessageSpecifications; /** *

* Constructor. Creates a new EventGenerationRule. *

* * @param ruleElement * the JDOM element that descripes the rule * @param rulesNamespace * the XML namespace the rule is defined in */ @SuppressWarnings("unchecked") EventGenerationRule(Element ruleElement, Namespace rulesNamespace) { this.namespace = rulesNamespace; this.name = ruleElement.getAttributeValue("name"); this.messageConditions = new ArrayList(); this.eventParameters = new ArrayList(); this.replayMessageSpecifications = new ArrayList(); for (Element child : (List) ruleElement.getChildren()) { if ("msg".equals(child.getName()) && namespace.equals(child.getNamespace())) { messageConditions.add(new MessageCondition(child)); } else if ("idinfo".equals(child.getName()) && namespace.equals(child.getNamespace())) { for (Element parameterElements : (List) child.getChildren()) { eventParameters.add(new Term(parameterElements)); } } else if ("genMsg".equals(child.getName()) && namespace.equals(child.getNamespace())) { replayMessageSpecifications.add(new ReplayMessageSpec(child)); } else if ("genMsgSeq".equals(child.getName()) && namespace.equals(child.getNamespace())) { replayMessageSpecifications.add(new ReplayMessageSpec(child)); } else { throw new IllegalArgumentException( "the provided rules can not be parsed: unknown element " + child.getName()); } } } /** *

* Returns the name of the rule. *

* * @return the name */ String getName() { return name; } /** *

* Returns the conditions on the matched messages defined by this rule. *

* * @return the message conditions */ List getMessageConditions() { return messageConditions; } /** *

* Returns the parameters of the event generated by this rule. *

* * @return the event parameters */ List getEventParameters() { return eventParameters; } /** *

* Returns the replay specification defined by this rule. *

* * @return the replay specification */ List getReplayMessageSpecifications() { return replayMessageSpecifications; } /** *

* Helper class that describes conditions on the message sequence when matching this rule. *

* * @version 1.0 * @author Steffen Herbold, Patrick Harms */ class MessageCondition { /** *

* True, if the condition defines to match several conditions *

*/ private boolean matchMultiple; /** *

* Type of the message matched by the condition *

*/ private WindowsMessageType messageType; /** *

* Term conditions associated with the rule condition *

*/ private List attributeConditions; /** *

* List of messages to be stored, if the message matches, for continuing the rule * application *

*/ private ArrayList messagesToStore; /** *

* Constructor. Creates a new MessageCondition. *

* * @param msgChild * JDOM element that describes the message condition */ @SuppressWarnings("unchecked") private MessageCondition(Element msgChild) { this.matchMultiple = "true".equals(msgChild.getAttributeValue("multiple")); this.messageType = WindowsMessageType.parseMessageType(msgChild.getAttributeValue("type")); this.attributeConditions = new ArrayList(); for (Element childElement : (List) msgChild.getChildren("equals", namespace)) { attributeConditions.add(new AttributeCondition(childElement)); } this.messagesToStore = new ArrayList(); for (Element childElement : (List) msgChild.getChildren("store", namespace)) { messagesToStore.add(new Term(childElement)); } for (Element childElement : (List) msgChild.getChildren("storeSeq", namespace)) { messagesToStore.add(new Term(childElement)); } } /** *

* Returns whether a single message is matched to the condition or a whole sequence can be * matched. *

* * @return true if multiple message shall be matched, false if only a single message is * matched */ boolean matchMultiple() { return matchMultiple; } /** *

* Returns the type of the matched messages. *

* * @return the message type */ WindowsMessageType getMessageType() { return messageType; } /** *

* Returns the attribute conditions of the message condition. *

* * @return the attribute conditions */ List getAttributeConditions() { return attributeConditions; } /** *

* Returns messages, that have eventually been stored as part of the condition. *

* * @return the stored messages */ ArrayList getMessagesToStore() { return messagesToStore; } } /** *

* Helper class that defines attribute conditions for matching messages. *

* * @version 1.0 * @author Steffen Herbold, Patrick Harms */ class AttributeCondition { /** *

* Left hand side of the condition. *

*/ private Term leftHandSide; /** *

* Reft hand side of the condition. *

*/ private Term rightHandSide; /** *

* Constructor. Creates a new AttributeCondition. *

* * @param conditionElement * JDOM element that describes the condition */ private AttributeCondition(Element conditionElement) { this.leftHandSide = new Term((Element) conditionElement.getChildren().get(0)); this.rightHandSide = new Term((Element) conditionElement.getChildren().get(1)); } /** *

* Returns the left hand side of the condition. *

* * @return the left hand side */ Term getLeftHandSide() { return leftHandSide; } /** *

* Returns the right hand side of the condition. *

* * @return the right hand side */ Term getRightHandSide() { return rightHandSide; } } /** *

* Helper class that defines terms to define conditions. *

* * @version 1.0 * @author Steffen Herbold, Patrick Harms */ class Term { /** *

* Name of the term. *

*/ private String name; /** *

* Value of the term, if it is a constValue; null otherwise. *

*/ private String value; /** *

* Variable name of the object, i.e. a message, of which a parameter is identified if the * term is a winInfoValue or a msgInfoValue; null otherwise. *

*/ private String messageId; /** *

* Name of the parameter of the object, i.e., a message, of which a parameter is identified * if the term is a paramValue; null otherwise. *

*/ private String messageParameterName; /** *

* Variable name of the message sequence denoted by the term in case of a seqValue; null * otherwise. *

*/ private String sequenceId; /** *

* Name of the parameter of the sequence of which a parameter is identified if the term is a * seqValue; null otherwise. *

*/ private String sequenceParameterName; /** *

* Name of the parameter of the window of the object, e.g. a message, of which a parameter * is identified if the term is a winInfoValue; null otherwise. *

*/ private String windowParameterName; /** *

* Name of the info of the message of which a parameter is identified if the term is a * msgInfoValue; null otherwise. *

*/ private String messageInfoName; /** *

* Name of the parameter of the message into which a value shall be stored if the term is a * resolveHwnd, null otherwise *

*/ private String storeParameterName; /** *

* List of handles to be resolved in case the term is a store or storeSeq; null otherwise. *

*/ private List resolveHandles; /** *

* Constructor. Creates a new Term. *

* * @param termElement * JDOM element that describes the term */ @SuppressWarnings("unchecked") private Term(Element termElement) { this.name = termElement.getName(); if ("constValue".equals(name)) { this.value = termElement.getAttributeValue("value"); } else if ("paramValue".equals(name)) { this.messageId = termElement.getAttributeValue("obj"); this.messageParameterName = termElement.getAttributeValue("param"); } else if ("winInfoValue".equals(name)) { this.messageId = termElement.getAttributeValue("obj"); this.windowParameterName = termElement.getAttributeValue("winParam"); } else if ("msgInfoValue".equals(name)) { this.messageId = termElement.getAttributeValue("obj"); this.messageInfoName = termElement.getAttributeValue("msgParam"); } else if ("seqValue".equals(name)) { this.sequenceId = termElement.getAttributeValue("seqObj"); this.sequenceParameterName = termElement.getAttributeValue("param"); } else if ("store".equals(name)) { this.messageId = termElement.getAttributeValue("var"); if ((termElement.getChildren() != null) && (termElement.getChildren().size() > 0)) { this.resolveHandles = new ArrayList(); for (Element child : (List) termElement.getChildren()) { this.resolveHandles.add(new Term(child)); } } } else if ("storeSeq".equals(name)) { this.sequenceId = termElement.getAttributeValue("varSeq"); if ((termElement.getChildren() != null) && (termElement.getChildren().size() > 0)) { this.resolveHandles = new ArrayList(); for (Element child : (List) termElement.getChildren()) { this.resolveHandles.add(new Term(child)); } } } else if ("resolveHwnd".equals(name)) { this.messageParameterName = termElement.getAttributeValue("param"); this.storeParameterName = termElement.getAttributeValue("storeParam"); } } /** *

* Returns the name of the term. *

* * @return the name */ String getName() { return name; } /** *

* Returns the value of the term. *

* * @return the value */ String getValue() { return value; } /** *

* Returns the object Id of the message, which is resolved as part of this term. *

* * @return the object Id */ String getMessageId() { return messageId; } /** *

* Returns the name of the message parameter that is resolved as part of this term. *

* * @return the message parameter name */ String getMessageParameterName() { return messageParameterName; } /** *

* Returns the object Id of the message sequence, which is resolved as part of this term. *

* * @return the object Id */ String getSequenceId() { return sequenceId; } /** *

* Returns the name of the message parameter that is resolved as part of this term. *

* * @return the sequenceParameter */ String getSequenceParameterName() { return sequenceParameterName; } /** *

* Returns the window parameter name that is resolved as part of this term. *

* * @return the name of the window parameter */ String getWindowParameterName() { return windowParameterName; } /** *

* Returns the name of the message info value that is resolved as part of this term. *

* * @return the name of the message info value */ String getMessageInfoName() { return messageInfoName; } /** *

* Returns the object Id under which a message will be stored. *

* * @return the object Id */ String getStoreParameterName() { return storeParameterName; } /** *

* Returns all terms that are responsible to resolve HWNDs. *

* * @return the terms */ List getResolveHandles() { return resolveHandles; } } /** *

* Helper class that defines the replay specification part of rules. *

* * @version 1.0 * @author Steffen Herbold, Patrick Harms */ class ReplayMessageSpec { /** *

* Determines if this specification defines one, or a sequence of messages. *

*/ private boolean generateSingleMessage; /** *

* Object Id of a concrete message of message sequence to be replayed as is. *

*/ private String replayObjectId; /** *

* Term describing the type of the generated message. *

*/ private Term type; /** *

* Term describing the target of the generated message. *

*/ private Term target; /** *

* Term describing the LO word of the LParam of the generated message. *

*/ private Term lparamLoWord; /** *

* Term describing the HI word of the LParam of the generated message. *

*/ private Term lparamHiWord; /** *

* Term describing the LParam of the generated message. *

*/ private Term lparam; /** *

* Term describing the LO word of the WParam of the generated message. *

*/ private Term wparamLoWord; /** *

* Term describing the HI word of the WParam of the generated message. *

*/ private Term wparamHiWord; /** *

* Term describing the WParam of the generated message. *

*/ private Term wparam; /** *

* Value in milliseconds that the replay waits until the the next message is replayed. *

*/ private int delay; /** *

* Constructor. Creates a new ReplayMessageSpec. *

* * @param replayMessageSpecElement * JDOM element that describes the replay message specification */ @SuppressWarnings("unchecked") private ReplayMessageSpec(Element replayMessageSpecElement) { List children = replayMessageSpecElement.getChildren(); if ("genMsg".equals(replayMessageSpecElement.getName())) { generateSingleMessage = true; if (children.size() == 1) { replayObjectId = children.get(0).getAttributeValue("obj"); } } else { generateSingleMessage = false; if (children.size() == 1) { replayObjectId = children.get(0).getAttributeValue("seqObj"); } } this.delay = Integer.parseInt(replayMessageSpecElement.getAttributeValue("delay")); if (children.size() > 1) { for (Element child : children) { Element termElement = (Element) child.getChildren().get(0); if (child.getName().equals("type")) { this.type = new Term(termElement); } else if (child.getName().equals("target")) { this.target = new Term(termElement); if (!generateSingleMessage) { // in this case, the target is always a sequence value term, i.e. // the targets of the originally recorded sequence. So the // replay object id is set to this sequence replayObjectId = target.getSequenceId(); } } else if (child.getName().equals("LPARAM")) { Element loWordElement = child.getChild("LOWORD", namespace); if (loWordElement != null) { this.lparamLoWord = new Term((Element) loWordElement.getChildren().get(0)); } Element hiWordElement = child.getChild("HIWORD", namespace); if (hiWordElement != null) { this.lparamHiWord = new Term((Element) hiWordElement.getChildren().get(0)); } if ((lparamLoWord == null) && (lparamHiWord == null)) { this.lparam = new Term(termElement); } } else if (child.getName().equals("WPARAM")) { Element loWordElement = child.getChild("LOWORD", namespace); if (loWordElement != null) { this.wparamLoWord = new Term((Element) loWordElement.getChildren().get(0)); } Element hiWordElement = child.getChild("HIWORD", namespace); if (hiWordElement != null) { this.wparamHiWord = new Term((Element) hiWordElement.getChildren().get(0)); } if ((wparamLoWord == null) && (wparamHiWord == null)) { this.wparam = new Term(termElement); } } } } } /** *

* Determines if this specification defines one, or a sequence of messages. *

* * @return true if only a single message is generated; false if a sequence is generated */ boolean generateSingleMessage() { return generateSingleMessage; } /** *

* Returns the object Id from which the message is generated. *

* * @return the object Id */ String getReplayObjectId() { return replayObjectId; } /** *

* Returns the term that describes the type of the generated message. *

* * @return the type term */ Term getType() { return type; } /** *

* Returns the term that describes the target of the generated message. *

* * @return the target term */ Term getTarget() { return target; } /** *

* Returns the term that describes the LO word of the LParam of the generated message. *

* * @return the LParam LO word term */ Term getLparamLoWord() { return lparamLoWord; } /** *

* Returns the term that describes the HI word of the LParam of the generated message. *

* * @return the LParam HI word term */ Term getLparamHiWord() { return lparamHiWord; } /** *

* Returns the term that describes the LParam of the generated message. *

* * @return the LParam term */ Term getLparam() { return lparam; } /** *

* Returns the term that describes the LO word of the WParam of the generated message. *

* * @return the WParam LO word term */ Term getWparamLoWord() { return wparamLoWord; } /** *

* Returns the term that describes the HI word of the WParam of the generated message. *

* * @return the WParam HI word term */ Term getWparamHiWord() { return wparamHiWord; } /** *

* Returns the term that describes the WParam of the generated message. *

* * @return the WParam term */ Term getWparam() { return wparam; } /** *

* Returns the delay during the replay after this message is sent. *

* * @return the delay */ int getDelay() { return delay; } } }