// 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.taskequality.TaskEquality; import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEqualityRuleManager; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskBuilder; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskFactory; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList; import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession; import de.ugoe.cs.util.console.Console; /** * TODO update comment * *

* 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 tasks which are not only a major sequence. I.e. through the application of the * rules iterations and selections of tasks are detected. Which kind of temporal relations * between tasks are detected depends on the {@link ITaskInstanceListScopeRule}s known to * this class. *

*

The class holds references to the appropriate {@link ITaskInstanceListScopeRule}s and calls * their {@link ITaskInstanceListScopeRule#apply(ITask, ITaskBuilder, ITaskFactory, boolean)} * method for each task 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(ITask, ITaskBuilder, ITaskFactory, boolean)} * method is called for a so far unstructured task *
  4. *
  5. * the class iterates its internal list of rules and calls their * {@link ITaskInstanceListScopeRule#apply(ITask, ITaskBuilder, ITaskFactory, 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 task and * all parent tasks created during the rule application. *

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

* the task equality manager needed by the rules to compare tasks with each other *

*/ private TaskEqualityRuleManager taskEqualityRuleManager; /** *

* the task factory to be used during rule application *

*/ private ITaskFactory taskFactory; /** *

* the task builder to be used during rule application *

*/ private ITaskBuilder taskBuilder; /** *

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

*/ private ISessionScopeRule[] sessionScopeRules; /** *

* 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 ITaskInstanceListScopeRule[] taskScopeRules; /** *

* initialize the manager *

* * @param taskEqualityRuleManager the task equality rule manager to be used by the known rules * for task comparison during rule application * @param taskFactory the task factory to be used for instantiating new task tree * tasks during rule application * @param taskBuilder the task builder to be used for linking tasks * with each other during rule application */ public TemporalRelationshipRuleManager(TaskEqualityRuleManager taskEqualityRuleManager, ITaskFactory taskFactory, ITaskBuilder taskBuilder) { super(); this.taskEqualityRuleManager = taskEqualityRuleManager; this.taskFactory = taskFactory; this.taskBuilder = taskBuilder; } /** *

* initialized the temporal relationship rule manager by instantiating the known rules and * providing them with a reference to the task 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); sessionScopeRules = new ISessionScopeRule[] { new SequenceForTaskDetectionRule (taskEqualityRuleManager, TaskEquality.SEMANTICALLY_EQUAL, taskFactory, taskBuilder), /*new DefaultTaskSequenceDetectionRule (taskEqualityRuleManager, NodeEquality.SYNTACTICALLY_EQUAL, taskFactory, taskTreeBuilder), new DefaultTaskSequenceDetectionRule (taskEqualityRuleManager, NodeEquality.LEXICALLY_EQUAL, taskFactory, taskTreeBuilder),*/ /*new TreeScopeWrapperRule (new DefaultIterationDetectionRule (taskEqualityRuleManager, NodeEquality.LEXICALLY_EQUAL, taskFactory, taskTreeBuilder)), new TreeScopeWrapperRule (new DefaultIterationDetectionRule (taskEqualityRuleManager, NodeEquality.SYNTACTICALLY_EQUAL, taskFactory, taskTreeBuilder)), new TreeScopeWrapperRule (new DefaultIterationDetectionRule (taskEqualityRuleManager, NodeEquality.SEMANTICALLY_EQUAL, taskFactory, taskTreeBuilder))*/ }; //treeScopeRules.add(new DefaultGuiElementSequenceDetectionRule(frameFilter)); taskScopeRules = new ITaskInstanceListScopeRule[] { //new SequenceOnGuiElementDetectionRule(taskFactory, taskTreeBuilder), //new EventSequenceOnSameTargetDetectionRule(taskFactory, taskTreeBuilder), //new TrackBarSelectionDetectionRule(taskEqualityRuleManager, taskFactory, taskBuilder), //new DefaultGuiEventSequenceDetectionRule(taskFactory, taskTreeBuilder), }; } /** *

* applies the known rules to the provided sessions. For the creation of further tasks, * the provided builder and task factory are utilized. The method expects, that no more data * is available and, therefore, finalizes the rule application. *

* * @param taskFactory the task factory to be used for instantiating new tasks. */ public void applyRules(List sessions) { applyRules(sessionScopeRules, sessions, ""); } /** *

* applies the known rules to the provided parent task. For the creation of further tasks, * the provided builder and task 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 task created through the rule * application. In this case, the finalize parameter is always true. *

* * @param parent the parent task 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(ISessionScopeRule[] rules, List sessions, String logIndent) { Console.traceln (Level.FINER, logIndent + "applying rules for " + sessions.size() + " sessions"); int noOfRuleApplications = 0; for (ISessionScopeRule rule : rules) { RuleApplicationResult result; do { Console.traceln(Level.FINER, logIndent + "trying rule " + rule); result = rule.apply(sessions); if ((result != null) && (result.getRuleApplicationStatus() == RuleApplicationStatus.FINISHED)) { Console.traceln(Level.FINE, logIndent + "applied rule " + rule); noOfRuleApplications++; //dumpTask(parent, ""); for (ITaskInstance newParent : result.getNewlyCreatedTaskInstances()) { noOfRuleApplications += applyRules(taskScopeRules, newParent, logIndent + " "); } } } while ((result != null) && (result.getRuleApplicationStatus() == RuleApplicationStatus.FINISHED)); } if (noOfRuleApplications <= 0) { Console.traceln(Level.FINE, logIndent + "no rules applied --> no temporal " + "relationship generated"); } return noOfRuleApplications; } /** *

* applies the known rules to the provided parent task. For the creation of further tasks, * the provided builder and task 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 task created through the rule * application. In this case, the finalize parameter is always true. *

* * @param parent the parent task 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(ITaskInstanceListScopeRule[] rules, ITaskInstanceList taskInstances, String logIndent) { Console.traceln(Level.FINER, logIndent + "applying rules for " + taskInstances.size() + " task instances"); int noOfRuleApplications = 0; for (ITaskInstanceListScopeRule rule : rules) { RuleApplicationResult result; do { Console.traceln (Level.FINER, logIndent + "trying rule " + rule + " on " + taskInstances); result = rule.apply(taskInstances); if ((result != null) && (result.getRuleApplicationStatus() == RuleApplicationStatus.FINISHED)) { Console.traceln (Level.FINE, logIndent + "applied rule " + rule + " on " + taskInstances); noOfRuleApplications++; //dumpTask(parent, ""); for (ITaskInstance newParent : result.getNewlyCreatedTaskInstances()) { noOfRuleApplications += applyRules(taskScopeRules, newParent, logIndent + " "); } } } while ((result != null) && (result.getRuleApplicationStatus() == RuleApplicationStatus.FINISHED)); } if (noOfRuleApplications <= 0) { Console.traceln(Level.FINE, logIndent + "no rules applied --> no temporal " + "relationship generated"); } return noOfRuleApplications; } /** * */ /*private void dumpTask(ITask 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 (ITask child : task.getChildren()) { dumpTask(child, indent + " "); } } }*/ }