Some API docs for the entering/reentering part

This commit is contained in:
Óscar González Fernández 2012-03-01 13:34:56 +01:00 committed by Jacobo Aragunde Pérez
parent 59c8a98a72
commit 7665af0247

View file

@ -550,13 +550,44 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
public void setNewEnd(GanttDate previousEnd, GanttDate newEnd);
}
/**
* <p>
* When a {@link Task}'s dates are modified methods of this interface must
* be called. This can potentially trigger the dependencies enforcement
* algorithm.
* </p>
* <p>
* If the date modification happens outside the dependencies enforcement
* algorithm, it's always executed. Through the algorithm execution other
* tasks' dates are modified. When this happens we don't want to trigger the
* algorithm, instead we want to record that the change has happened and
* when the algorithm ends all the tasks are notified at once.
* </p>
* <p>
* For example imagine a Gantt with three tasks: T1 -> T2 -> T3. Imagine
* that T1 position is modified due to being moved by the user. In that case
* the scheduling algorithm triggers and the {@link Recalculation
* recalculations} needed are done. T2 position would be recalculated and T3
* position too. When the recalculation happens their dates are modified,
* but in that case we don't want to trigger the dependencies enforcement
* algorithm again. What we want is to record the changes that have happened
* due to the algorithm. When the algorithm ends all notifications are fired
* at once. These notifications are notified to the registered
* {@link INotificationAfterDependenciesEnforcement}.
* </p>
*/
public interface IDependenciesEnforcerHook extends IDependenciesEnforcer {
public void positionPotentiallyModified();
}
public interface IDependenciesEnforcerHookFactory<T> {
/**
* Creates a {@link IDependenciesEnforcerHook} that uses the provided
* {@link INotificationAfterDependenciesEnforcement notifier} to notify
* the changes that have happened due to the algorithm.
*/
public IDependenciesEnforcerHook create(T task,
INotificationAfterDependenciesEnforcement notification);
INotificationAfterDependenciesEnforcement notifier);
public IDependenciesEnforcerHook create(T task);
}
@ -580,6 +611,11 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
}
};
/**
* Tracks all modifications to dates that have happened inside the
* dependencies enforcement algorithm. At the end of the algorithm they're
* executed via {@link DeferedNotifier#doNotifications()}.
*/
public class DeferedNotifier {
private Map<V, NotificationPendingForTask> notificationsPending = new LinkedHashMap<V, NotificationPendingForTask>();
@ -697,6 +733,11 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
private ThreadLocal<DeferedNotifier> deferedNotifier = new ThreadLocal<DeferedNotifier>();
/**
* It creates a {@link IDependenciesEnforcerHook} that starts the
* algorithm <em>onEntrance</em> and in subsequent tasks position
* modifications records the changes <em>onNotification</em>.
*/
@Override
public IDependenciesEnforcerHook create(V task,
INotificationAfterDependenciesEnforcement notificator) {
@ -711,6 +752,10 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
return create(task, EMPTY_NOTIFICATOR);
}
/**
* What to do when a task's position is modified not inside the
* dependencies enforcement algorithm.
*/
private IDependenciesEnforcer onEntrance(final V task) {
return new IDependenciesEnforcer() {
@ -727,6 +772,10 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
};
}
/**
* What to do when a task's position is modified from inside the
* dependencies enforcement algorithm.
*/
private IDependenciesEnforcer onNotification(final V task,
final INotificationAfterDependenciesEnforcement notification) {
return new IDependenciesEnforcer() {
@ -751,6 +800,10 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
}
/**
* Enrich {@link IDependenciesEnforcer} with
* {@link IDependenciesEnforcerHook#positionPotentiallyModified()}.
*/
private IDependenciesEnforcerHook withPositionPotentiallyModified(
final V task, final IDependenciesEnforcer enforcer) {
return new IDependenciesEnforcerHook() {
@ -773,9 +826,18 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
};
}
/**
* Creates a {@link IDependenciesEnforcer} that detects if a position
* change comes from the dependencies algorithm or comes from outside.
* For that a {@link ReentranceGuard} is used. If the dependencies
* enforcement algorithm isn't being executed the
* {@link IDependenciesEnforcer} created delegates to
* <code>onEntrance</code>. Otherwise it delegates to
* <code>notifier</code>.
*/
private IDependenciesEnforcer onlyEnforceDependenciesOnEntrance(
final IDependenciesEnforcer onEntrance,
final IDependenciesEnforcer notification) {
final IDependenciesEnforcer notifier) {
return new IDependenciesEnforcer() {
@Override
@ -790,7 +852,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
@Override
public void doAction() {
notification.setStartDate(
notifier.setStartDate(
previousStart,
previousEnd, newStart);
onEntrance.setStartDate(
@ -802,7 +864,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
@Override
public void ifAlreadyInside() {
notification.setStartDate(previousStart,
notifier.setStartDate(previousStart,
previousEnd, newStart);
}
@ -821,7 +883,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
@Override
public void doAction() {
notification.setNewEnd(previousEnd,
notifier.setNewEnd(previousEnd,
newEnd);
onEntrance.setNewEnd(previousEnd,
newEnd);
@ -831,7 +893,7 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
@Override
public void ifAlreadyInside() {
notification.setNewEnd(previousEnd, newEnd);
notifier.setNewEnd(previousEnd, newEnd);
}
});
}
@ -878,10 +940,20 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
});
}
/**
* When entering and exiting the dependencies enforcement algorithm some
* listeners must be notified.
*/
private void onNewEntrance(final IAction action) {
preAndPostActions.doAction(decorateWithNotifications(action));
}
/**
* Attach the {@link DeferedNotifier} for the current execution.
* {@link DeferedNotifier#doNotifications()} is called once the
* execution has finished, telling all listeners the task positions
* modifications that have happened.
*/
private IAction decorateWithNotifications(final IAction action) {
return new IAction() {
@ -2347,6 +2419,24 @@ interface IReentranceCases {
public void ifAlreadyInside();
}
/**
* <p>
* It marks the start and the end part of a potentially reentering execution
* using a {@link ThreadLocal} variable. For example, some method execution can
* eventually be called again. When that methods is called we want to know if
* it's called within the execution of itself or from the outside. I.e., it's
* useful to do different things depending if the execution is already being
* done or entering in it.
* </p>
*
* <p>
* It can detect if it's already executing or not. If it is,
* {@link IReentranceCases#ifAlreadyInside()} is called, otherwise
* {@link IReentranceCases#ifNewEntrance()} is called.
* </p>
*
* @author Óscar González Fernández <ogfernandez@gmail.com>
*/
class ReentranceGuard {
private final ThreadLocal<Boolean> inside = new ThreadLocal<Boolean>() {
protected Boolean initialValue() {