// 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.manager; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import de.ugoe.cs.autoquest.eventcore.Event; import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality; import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskBuilder; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskFactory; import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession; import de.ugoe.cs.util.console.Console; /** *

* The task tree manager is responsible for transforming one or more user sessions into a task * model. It can be called by providing a collection of user sessions where the result * will be a task model. Furthermore, it can be used by providing single events in their respective * order including notifications about where a user session ends. The result is a task model, * as well. *

* * @version 1.0 * @author pharms */ public class TaskTreeManager { /** *

* the internally used task builder *

*/ private ITaskBuilder taskBuilder = ComponentManager.getDefaultTaskBuilder(); /** *

* the internally used task factory *

*/ private ITaskFactory taskFactory = ComponentManager.getDefaultTaskFactory(); /** *

* if single events are provided, the user sessions collected so far *

*/ private List sessions = null; /** *

* if single events are provided, the currently collected user session *

*/ private IUserSession currentSession = null; /** *

* The default task equality considered when comparing task instances initially *

*/ private TaskEquality minimalTaskEquality = TaskEquality.SEMANTICALLY_EQUAL; /** *

* If this flag is set, then the task tree manager will not create new event tasks for any * events. Instead, it will check using the hashcode and equal methods of the provided events * if a certain event has already occurred, and if so, the corresponding event task will be * reused. *

*/ private boolean useEventEqualityForTaskComparison; /** *

* the minimum number of event task instances a sequence must cover to still detect it as a * representative task *

*/ private int minimumSequenceCoverage;; /** *

* If the flag {@link #useEventEqualityForTaskComparison} is set, then here the task tree * manager stores the already created event tasks. *

*/ private Map eventTasks = new HashMap<>(); /** *

* initializes the task tree manager *

*/ public TaskTreeManager() { this.sessions = new LinkedList(); } /** *

* creates a task model based on the provided user sessions. Yet, the user sessions are * list of events. Such will be transformed in into task instances of event tasks assigned * to {@link IUserSession}s. The {@link IUserSession}s will then be restructured using * the temporal relationship rule manager to detect tasks and respective instances. The * results of this transformation is stored in a task model which is the return value of * this method. *

* * @param newSessions the user sessions of which the task model shall be created * * @return the task model created from the user sessions * * @throws IllegalStateException if the task manager is already used by providing it with * single events */ public synchronized ITaskModel createTaskModel(Collection> newSessions, boolean useEventEqualityForTaskComparison, int minimumSequenceCoverage) { if ((currentSession != null) || (sessions.size() > 0)) { throw new IllegalStateException("do not mix calls to this method with calls to the " + "other methods for handling tasks. Use only one " + "variant instead."); } this.useEventEqualityForTaskComparison = useEventEqualityForTaskComparison; if (useEventEqualityForTaskComparison) { // if we do this, we also need to consider identity of event tasks afterwards minimalTaskEquality = TaskEquality.IDENTICAL; } this.minimumSequenceCoverage = minimumSequenceCoverage; for (List newSession : newSessions) { if (newSession.size() > 0) { for (Event event : newSession) { handleNewEvent(event); } finishSession(); } } return getTaskModel(); } /** *

* call {@link #createTaskModel(Collection, boolean, int)} with false for use event equality * for comparison and 0 for the minimum number of covered events per sequence *

* * @param newSessions the user sessions of which the task model shall be created * * @return the task model created from the user sessions * * @throws IllegalStateException if the task manager is already used by providing it with * single events */ public synchronized ITaskModel createTaskModel(Collection> newSessions) { return createTaskModel(newSessions, false, 0); } /** *

* handles a single event that occurred in a user session. *

* * @param event the event to handle */ public synchronized void handleNewEvent(Event event) { assertSessionSequence(); if (!useEventEqualityForTaskComparison) { String description = event.getType().getName() + " \u21D2 " + event.getTarget(); IEventTask eventTask = taskFactory.createNewEventTask(description); taskBuilder.addExecutedTask (currentSession, taskFactory.createNewTaskInstance(eventTask, event)); } else { IEventTask eventTask = eventTasks.get(event); if (eventTask == null) { String description = event.getType().getName() + " \u21D2 " + event.getTarget(); eventTask = taskFactory.createNewEventTask(description); eventTasks.put(event, eventTask); } taskBuilder.addExecutedTask (currentSession, taskFactory.createNewTaskInstance(eventTask, event)); } } /** *

* used to denote, that all previously added events using {@link #handleNewEvent(Event)} * belong to the same session and that this session is now complete. All further events * will be added to a new session which may be ended using this method, as well. *

*/ public synchronized void finishSession() { if ((currentSession != null) && (currentSession.size() > 0)) { sessions.add(currentSession); currentSession = null; } } /** *

* returns the task model, that belongs to the events in the user sessions collected so far. *

* * @return the task model */ public synchronized ITaskModel getTaskModel() { finishSession(); Console.traceln (Level.INFO, "applying temporal relationship generation rules for detecting tasks"); ComponentManager.getTemporalRelationshipRuleManager().applyTaskDetectionRule (sessions, minimalTaskEquality, minimumSequenceCoverage); return taskFactory.createTaskModel(sessions); } /** *

* merges similar tasks in the given task model and returns a condensed task model *

* * @param inputModel the model with the tasks to be merged * * @return as described */ public synchronized ITaskModel mergeSimilarTasks(ITaskModel inputModel) { Console.traceln (Level.INFO, "applying temporal relationship generation rules for merging tasks"); sessions = inputModel.getUserSessions(); ComponentManager.getTemporalRelationshipRuleManager().applyTaskMergingRule(sessions); return taskFactory.createTaskModel(sessions); } /** *

* internally asserts that there is a current session to add new events to *

*/ private void assertSessionSequence() { if (currentSession == null) { currentSession = taskFactory.createUserSession(); } } }