// 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.io.IOException; import java.io.ObjectInputStream; import java.util.HashMap; import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality; import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEqualityRuleManager; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; import de.ugoe.cs.autoquest.usageprofiles.SymbolComparator; /** *

* implementation of a symbol comparator for task instances. Internally, it uses comparison buffers * to prevent comparing two tasks or task instances several times. It internally instantiates * comparers being the implementation strategy of the comparisons required for a specific level * of task equality. The comparers internally use the {@link TaskEqualityRuleManager} for * performing comparisons. *

*/ public class TaskInstanceComparator implements SymbolComparator { /** */ private static final long serialVersionUID = 1L; /** * the maximum size of the internal buffer used for storing comparison results */ private static final int MAX_BUFFER_SIZE = 2 * 1024 * 1024; /** * the considered level of task equality */ private TaskEquality minimalTaskEquality; /** * the comparer used internally for comparing two tasks */ private transient Comparer comparer; /** * the comparer used for comparing two tasks on the lexical level */ private transient Comparer lexicalComparer; /** * internal buffer used for storing comparison results */ private transient HashMap equalityBuffer = new HashMap(); /** * internal buffer used for storing comparison results only for lexical comparisons */ private transient HashMap lexicalEqualityBuffer; /** *

* initializes the comparator with a considered task equality level *

* * @param minimalTaskEquality the considered task equality level */ public TaskInstanceComparator(TaskEquality minimalTaskEquality) { this.minimalTaskEquality = minimalTaskEquality; init(); } /* (non-Javadoc) * @see SymbolComparator#equals(Object, Object) */ @Override public boolean equals(ITaskInstance taskInstance1, ITaskInstance taskInstance2) { return equals(taskInstance1.getTask(), taskInstance2.getTask()); } /** *

* returns true, if this comparator considers the provided tasks as equal, false else *

* * @param task1 the first task to compare * @param task2 the second task to compare * * @return as described */ public boolean equals(ITask task1, ITask task2) { Boolean result; if (task1 != task2) { //if ((task1 instanceof IEventTask) && (task2 instanceof IEventTask)) { long key = ((long) System.identityHashCode(task1)) << 32; key += System.identityHashCode(task2); result = equalityBuffer.get(key); if (result == null) { result = comparer.compare(task1, task2); if (equalityBuffer.size() < MAX_BUFFER_SIZE) { equalityBuffer.put(key, result); } } /*} else { result = false; }*/ } else { result = true; } return result; } /** *

* returns true, if this comparator considers the provided tasks as lexically equal, false else *

* * @param task1 the first task to compare * @param task2 the second task to compare * * @return as described */ public boolean areLexicallyEqual(ITask task1, ITask task2) { Boolean result; if (task1 != task2) { long key = ((long) System.identityHashCode(task1)) << 32; key += System.identityHashCode(task2); result = lexicalEqualityBuffer.get(key); if (result == null) { result = lexicalComparer.compare(task1, task2); if (equalityBuffer.size() < MAX_BUFFER_SIZE) { lexicalEqualityBuffer.put(key, result); } } } else { result = true; } return result; } /** *

* can be called externally to clear the internal comparison buffers *

*/ public void clearBuffers() { equalityBuffer.clear(); init(); } /** *

* initializes the comparator with comparers depending on the different comparison levels as * well as with the required comparison buffers. Comparers and buffers for lexical comparison * may be reused if the considered equality level is also lexical. *

*/ private void init() { if (minimalTaskEquality == TaskEquality.LEXICALLY_EQUAL) { comparer = new LexicalComparer(); } else if (minimalTaskEquality == TaskEquality.SYNTACTICALLY_EQUAL) { comparer = new SyntacticalComparer(); } else if (minimalTaskEquality == TaskEquality.SEMANTICALLY_EQUAL) { comparer = new SemanticalComparer(); } else { comparer = new DefaultComparer(this.minimalTaskEquality); } if (minimalTaskEquality == TaskEquality.LEXICALLY_EQUAL) { lexicalComparer = comparer; lexicalEqualityBuffer = equalityBuffer; } else { lexicalComparer = new LexicalComparer(); lexicalEqualityBuffer = new HashMap(); } } /** *

* deserialize this object and reinitialize the buffers *

*/ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); init(); } /** *

* interface for internally used comparers containing only a compare method *

*/ private static interface Comparer { /** *

* returns true, if this comparator considers the provided tasks as equal, false else *

* * @param task1 the first task to compare * @param task2 the second task to compare * * @return as described */ boolean compare(ITask task1, ITask task2); } /** *

* comparer that performs comparisons only on the lexical level *

*/ private static class LexicalComparer implements Comparer { /* (non-Javadoc) * @see Comparer#compare(ITask, ITask) */ public boolean compare(ITask task1, ITask task2) { return TaskEqualityRuleManager.getInstance().areLexicallyEqual(task1, task2); } } /** *

* comparer that performs comparisons only on the syntactical level *

* */ private static class SyntacticalComparer implements Comparer { /* (non-Javadoc) * @see Comparer#compare(ITask, ITask) */ public boolean compare(ITask task1, ITask task2) { return TaskEqualityRuleManager.getInstance().areSyntacticallyEqual(task1, task2); } } /** *

* comparer that performs comparisons only on the semantical level *

*/ private static class SemanticalComparer implements Comparer { /* (non-Javadoc) * @see Comparer#compare(ITask, ITask) */ public boolean compare(ITask task1, ITask task2) { return TaskEqualityRuleManager.getInstance().areSemanticallyEqual(task1, task2); } } /** *

* comparer that performs comparisons only on the provided level *

*/ private static class DefaultComparer implements Comparer { /** *

* the minimal task equality considered by this comparer *

*/ private TaskEquality minimalTaskEquality; /** *

* initializes this comparer with the task equality to be considered *

*/ public DefaultComparer(TaskEquality minimalTaskEquality) { this.minimalTaskEquality = minimalTaskEquality; } /* (non-Javadoc) * @see Comparer#compare(ITask, ITask) */ public boolean compare(ITask task1, ITask task2) { return TaskEqualityRuleManager.getInstance().areAtLeastEqual (task1, task2, minimalTaskEquality); } } }