Some API docs for the entering/reentering part
This commit is contained in:
parent
59c8a98a72
commit
7665af0247
1 changed files with 96 additions and 6 deletions
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue