// Copyright 2012 Georg-August-Universität Göttingen, Germany // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.ugoe.cs.autoquest.tasktrees.temporalrelation; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import de.ugoe.cs.autoquest.eventcore.guimodel.IDialog; import de.ugoe.cs.autoquest.eventcore.guimodel.IFrame; import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement; import de.ugoe.cs.autoquest.tasktrees.nodeequality.NodeEquality; import de.ugoe.cs.autoquest.tasktrees.nodeequality.NodeEqualityRuleManager; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeBuilder; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeNode; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskTreeNodeFactory; import de.ugoe.cs.util.console.Console; /** *

* This class is responsible for applying temporal relationship rules on a task tree. Through this, * a flat task tree is restructured to have more depth but to include more temporal relationships * between task tree nodes which are not only a major sequence. I.e. through the application of * rule iterations and selections of task tree nodes are detected. Which kind of temporal relations * between task tree nodes are detected depends on the {@link TemporalRelationshipRule}s known to * this class. *

*

The class holds references to the appropriate {@link TemporalRelationshipRule}s and calls * their {@link TemporalRelationshipRule#apply(ITaskTreeNode, ITaskTreeBuilder, ITaskTreeNodeFactory, boolean)} * method for each node in the task tree it is needed for. The general behavior of this class is * the following: *

    *
  1. * An instance of this class is created using the constructor and calling the * {@link #init()} method afterwards *
  2. *
  3. * then the {@link #applyRules(ITaskTreeNode, ITaskTreeBuilder, ITaskTreeNodeFactory, boolean)} * method is called for a so far unstructured task tree node *
  4. *
  5. * the class iterates its internal list of rules and calls their * {@link TemporalRelationshipRule#apply(ITaskTreeNode, ITaskTreeBuilder, ITaskTreeNodeFactory, boolean)} * method. *
  6. *
  7. * the class evaluates the rule application result * *
  8. *
* Through this, all rules are tried to be applied at least once to the provided parent node and * all parent nodes created during the rule application. *

* * @author Patrick Harms */ public class TemporalRelationshipRuleManager { /** *

* the node equality manager needed by the rules to compare task tree nodes with each other *

*/ private NodeEqualityRuleManager nodeEqualityRuleManager; /** *

* the task tree node factory to be used during rule application *

*/ private ITaskTreeNodeFactory taskTreeNodeFactory; /** *

* the task tree builder to be used during rule application *

*/ private ITaskTreeBuilder taskTreeBuilder; /** *

* the temporal relationship rules known to the manager that are executed on whole sub trees. * The rules are applied in the order they occur in this list. *

*/ private TemporalRelationshipRule[] treeScopeRules; /** *

* the temporal relationship rules known to the manager that are executed on whole sub trees. * The rules are applied in the order they occur in this list. *

*/ private TemporalRelationshipRule[] nodeScopeRules; /** *

* initialize the manager *

* * @param nodeEqualityRuleManager the node equality rule manager to be used by the known rules * for task tree node comparison during rule application * @param taskTreeNodeFactory the node factory to be used for instantiating new task tree * nodes during rule application * @param taskTreeBuilder the task tree builder to be used for linking task tree nodes * with each other during rule application */ public TemporalRelationshipRuleManager(NodeEqualityRuleManager nodeEqualityRuleManager, ITaskTreeNodeFactory taskTreeNodeFactory, ITaskTreeBuilder taskTreeBuilder) { super(); this.nodeEqualityRuleManager = nodeEqualityRuleManager; this.taskTreeNodeFactory = taskTreeNodeFactory; this.taskTreeBuilder = taskTreeBuilder; } /** *

* initialized the temporal relationship rule manager by instantiating the known rules and * providing them with a reference to the node equality manager or other information they need. *

*/ public void init() { List> frameFilter = new ArrayList>(); frameFilter.add(IFrame.class); frameFilter.add(IDialog.class); //frameFilter.add(ICanvas.class); treeScopeRules = new TemporalRelationshipRule[] { new SequenceForTaskDetectionRule (nodeEqualityRuleManager, NodeEquality.SEMANTICALLY_EQUAL, taskTreeNodeFactory, taskTreeBuilder), /*new DefaultTaskSequenceDetectionRule (nodeEqualityRuleManager, NodeEquality.SYNTACTICALLY_EQUAL, taskTreeNodeFactory, taskTreeBuilder), new DefaultTaskSequenceDetectionRule (nodeEqualityRuleManager, NodeEquality.LEXICALLY_EQUAL, taskTreeNodeFactory, taskTreeBuilder),*/ /*new TreeScopeWrapperRule (new DefaultIterationDetectionRule (nodeEqualityRuleManager, NodeEquality.LEXICALLY_EQUAL, taskTreeNodeFactory, taskTreeBuilder)), new TreeScopeWrapperRule (new DefaultIterationDetectionRule (nodeEqualityRuleManager, NodeEquality.SYNTACTICALLY_EQUAL, taskTreeNodeFactory, taskTreeBuilder)), new TreeScopeWrapperRule (new DefaultIterationDetectionRule (nodeEqualityRuleManager, NodeEquality.SEMANTICALLY_EQUAL, taskTreeNodeFactory, taskTreeBuilder))*/ }; //treeScopeRules.add(new DefaultGuiElementSequenceDetectionRule(frameFilter)); nodeScopeRules = new TemporalRelationshipRule[] { //new SequenceOnGuiElementDetectionRule(taskTreeNodeFactory, taskTreeBuilder), //new EventSequenceOnSameTargetDetectionRule(taskTreeNodeFactory, taskTreeBuilder), new TrackBarSelectionDetectionRule (nodeEqualityRuleManager, taskTreeNodeFactory, taskTreeBuilder), //new DefaultGuiEventSequenceDetectionRule(taskTreeNodeFactory, taskTreeBuilder), }; } /** *

* applies the known rules to the provided parent node. For the creation of further nodes, * the provided builder and node factory are utilized. The method expectes, that no more data * is available and, therefore, finalizes the rule application. *

* * @param nodeFactory the node factory to be used for instantiating new task tree nodes. */ public void applyRules(ITaskTreeNode parent) { applyRules(parent, true); } /** *

* applies the known rules to the provided parent node. For the creation of further nodes, * the provided builder and node factory are utilized. If the finalize parameter is true, the * rule application is finalized as far as possible without waiting for further data. If it is * false, the rule application is broken up at the first rule returning, that its application * would be feasible. *

* * @param parent the parent node to apply the rules on * @param finalize used to indicate, if the rule application shall break up if a rule would * be feasible if further data was available, or not. */ public void applyRules(ITaskTreeNode parent, boolean finalize) { applyRules(treeScopeRules, parent, finalize, ""); } /** *

* applies the known rules to the provided parent node. For the creation of further nodes, * the provided builder and node factory are utilized. If the finalize parameter is true, the * rule application is finalized as far as possible without waiting for further data. If it is * false, the rule application is broken up at the first rule returning, that its application * would be feasible. The method calls itself for each parent node created through the rule * application. In this case, the finalize parameter is always true. *

* * @param parent the parent node to apply the rules on * @param finalize used to indicate, if the rule application shall break up if a rule would * be feasible if further data was available, or not. * @param logIndent simply used for logging purposes to indent the log messages depending * on the recursion depth of calling this method. */ private int applyRules(TemporalRelationshipRule[] rules, ITaskTreeNode parent, boolean finalize, String logIndent) { Console.traceln(Level.FINER, logIndent + "applying rules for " + parent); int noOfRuleApplications = 0; for (TemporalRelationshipRule rule : rules) { RuleApplicationResult result; do { Console.traceln(Level.FINER, logIndent + "trying rule " + rule + " on " + parent); result = rule.apply(parent, finalize); if ((result != null) && (result.getRuleApplicationStatus() == RuleApplicationStatus.FINISHED)) { Console.traceln (Level.FINE, logIndent + "applied rule " + rule + " on " + parent); noOfRuleApplications++; //dumpTask(parent, ""); for (ITaskTreeNode newParent : result.getNewlyCreatedParentNodes()) { noOfRuleApplications += applyRules(nodeScopeRules, newParent, true, logIndent + " "); } } } while ((result != null) && (result.getRuleApplicationStatus() == RuleApplicationStatus.FINISHED)); if ((!finalize) && (result != null) && (result.getRuleApplicationStatus() == RuleApplicationStatus.FEASIBLE)) { // in this case, don't go on applying rules, which should not be applied yet break; } } if (noOfRuleApplications <= 0) { Console.traceln(Level.FINE, logIndent + "no rules applied --> no temporal " + "relationship generated"); } return noOfRuleApplications; } /** * */ /*private void dumpTask(ITaskTreeNode task, String indent) { StringBuffer message = new StringBuffer(); message.append(indent); message.append(task); if (task.getDescription() != null) { message.append('('); message.append(task.getDescription()); message.append(')'); } Console.traceln(Level.FINER, message.toString()); if ((task.getChildren() != null) && (task.getChildren().size() > 0)) { for (ITaskTreeNode child : task.getChildren()) { dumpTask(child, indent + " "); } } }*/ }