X-Git-Url: https://mograsim.net/gitweb/?a=blobdiff_plain;f=plugins%2Fnet.mograsim.plugin.core%2Fsrc%2Fnet%2Fmograsim%2Fplugin%2Fnature%2FMachineContext.java;h=55316813aa6ef7f86d6597cd738660c4e06ddc85;hb=500771048185ce356aed280970f5ff0f4473a146;hp=2e02e31dff0c0dfb7914718aef1174851d4768a1;hpb=3f220100b4be4fa162f33b1434b55ce982be7be3;p=Mograsim.git diff --git a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java index 2e02e31d..55316813 100644 --- a/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java +++ b/plugins/net.mograsim.plugin.core/src/net/mograsim/plugin/nature/MachineContext.java @@ -1,5 +1,7 @@ package net.mograsim.plugin.nature; +import static net.mograsim.plugin.nature.MachineContextStatus.*; + import java.io.IOException; import java.util.HashSet; import java.util.Objects; @@ -7,6 +9,7 @@ import java.util.Optional; import java.util.Set; import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.ui.preferences.ScopedPreferenceStore; @@ -15,23 +18,34 @@ import net.mograsim.machine.MachineDefinition; import net.mograsim.machine.MachineRegistry; import net.mograsim.plugin.nature.ProjectContextEvent.ProjectContextEventType; +/** + * A MachineContext is a project specific context for the Mograsim machine associated to them. + *

+ * It stores the {@link MachineDefinition#getId() machine id}, the {@link MachineDefinition} if applicable and an active machine if present. + * {@link ActiveMachineListener}s and {@link MachineContextStatusListener}s can be used to track the state of the MachineContext. + * + * @author Christian Femers + * + */ public class MachineContext { - IProject owner; - ScopedPreferenceStore prefs; - Optional machineId; - Optional machineDefinition; - Optional activeMachine; + final IProject owner; + final ScopedPreferenceStore prefs; + Optional machineId = Optional.empty(); + Optional machineDefinition = Optional.empty(); + Optional activeMachine = Optional.empty(); + + private MachineContextStatus status = UNKOWN; - private final Set observers = new HashSet<>(); + private final Set machineListeners = new HashSet<>(); + private final Set stateListeners = new HashSet<>(); public MachineContext(IProject owner) { this.owner = Objects.requireNonNull(owner); prefs = ProjectMachineContext.getProjectPrefs(owner); prefs.addPropertyChangeListener(this::preferenceListener); - machineId = ProjectMachineContext.getMachineIdFrom(prefs); - updateDefinition(); + updateDefinition(ProjectMachineContext.getMachineIdFrom(prefs)); } public final IProject getProject() @@ -49,15 +63,17 @@ public class MachineContext */ public final boolean isCurrentyValid() { - return machineDefinition.isPresent(); + return status == READY || status == ACTIVE; } /** * Returns true if the persisted project configuration itself is intact + * + * @see MachineContextStatus#INTACT */ public final boolean isIntact() { - return machineId.isPresent(); + return isCurrentyValid() || status == INTACT; } /** @@ -65,7 +81,15 @@ public class MachineContext */ public final boolean isActive() { - return activeMachine.isPresent(); + return status == ACTIVE || status == ACTIVE_CHANGED; + } + + /** + * Returns the current status of this machine context + */ + public final MachineContextStatus getStatus() + { + return status; } /** @@ -92,7 +116,8 @@ public class MachineContext public final void setActiveMachine(Machine machine) { activeMachine = Optional.ofNullable(machine); - notifyObservers(); + updateStatus(); + notifyActiveMachineListeners(); } public final Optional getMachineId() @@ -107,13 +132,107 @@ public class MachineContext public final Optional getActiveMachine() { +// activateMachine(); // TODO is this the best way to deal with this? return activeMachine; } - final void updateDefinition() + /** + * Tries to activate the associated machine. This will not succeed if the project is not {@link MachineContextStatus#READY}. If the + * status is {@link MachineContextStatus#ACTIVE}, this method has no effect. + * + * @return true if the activation was successful + */ + public final boolean activateMachine() { - machineDefinition = machineId.map(MachineRegistry::getMachine); + if (status == ACTIVE) + return true; machineDefinition.ifPresent(md -> setActiveMachine(md.createNew())); + if (activeMachine.isPresent()) + System.out.format("Created new machine %s for project %s%n", activeMachine.get().getDefinition().getId(), owner.getName()); + updateStatus(); + return isActive(); + } + + /** + * This changes the internal status to a newly evaluated one and calls the {@link MachineContextStatusListener}s if this caused the + * status to change. + * + * @see #reevaluateStatus() + * @see #getStatus() + */ + public final void updateStatus() + { + MachineContextStatus newStatus = reevaluateStatus(); + forceUpdateStatus(newStatus); + } + + final void forceUpdateStatus(MachineContextStatus newStatus) + { + MachineContextStatus oldStatus = status; + if (oldStatus == newStatus) + return; + status = newStatus; + System.out.format("Project %s context status: %s -> %s%n", owner.getName(), oldStatus, newStatus); + doPostStatusChangedAction(); + notifyMachineContextStatusListeners(oldStatus); + } + + /** + * This method reevaluates the status but does not change/update it.
+ * To update the status of the {@link MachineContext}, use {@link #updateStatus()}. + * + * @return the raw status of the project at the time of the call. + */ + public final MachineContextStatus reevaluateStatus() + { + if (!owner.exists()) + return DEAD; + if (!owner.isOpen()) + return CLOSED; + if (hasInvaildMograsimProject()) + return BROKEN; + if (machineDefinition.isEmpty()) + return INTACT; + if (activeMachine.isEmpty()) + return READY; + if (!activeMachine.get().getDefinition().getId().equals(machineDefinition.get().getId())) + return ACTIVE_CHANGED; + return ACTIVE; + } + + private void doPostStatusChangedAction() + { + if ((status == DEAD || status == CLOSED) && activeMachine.isPresent()) + { + System.out.format("Removed machine %s for project %s%n", activeMachine.get().getDefinition().getId(), owner.getName()); + activeMachine = Optional.empty(); + notifyActiveMachineListeners(); + } + } + + private boolean hasInvaildMograsimProject() + { + try + { + if (!owner.isNatureEnabled(MograsimNature.NATURE_ID)) + return true; + return machineId.isEmpty(); + } + catch (CoreException e) + { + // cannot happen, because this method is called after the exceptional states were checked. + e.printStackTrace(); + return false; + } + } + + final void updateDefinition(Optional newMachineDefinitionId) + { + if (newMachineDefinitionId.equals(machineId)) + return; + machineId = newMachineDefinitionId; + machineDefinition = machineId.map(MachineRegistry::getMachine); + updateStatus(); ProjectMachineContext.notifyListeners(new ProjectContextEvent(this, ProjectContextEventType.MACHINE_DEFINITION_CHANGE)); } @@ -121,25 +240,40 @@ public class MachineContext { if (changeEvent.getProperty().equals(ProjectMachineContext.MACHINE_PROPERTY)) { - machineId = Optional.ofNullable((String) changeEvent.getNewValue()); - updateDefinition(); + updateDefinition(Optional.ofNullable((String) changeEvent.getNewValue())); } } - public void registerObserver(ActiveMachineListener ob) + private void notifyActiveMachineListeners() { - observers.add(ob); + machineListeners.forEach(ob -> ob.setMachine(activeMachine)); + } + + public void addActiveMachineListener(ActiveMachineListener ob) + { + machineListeners.add(ob); ob.setMachine(activeMachine); } - public void deregisterObserver(ActiveMachineListener ob) + public void removeActiveMachineListener(ActiveMachineListener ob) { - observers.remove(ob); + machineListeners.remove(ob); } - private void notifyObservers() + private void notifyMachineContextStatusListeners(MachineContextStatus oldStatus) { - observers.forEach(ob -> ob.setMachine(activeMachine)); + MachineContextStatus newStatus = status; + stateListeners.forEach(ob -> ob.updateStatus(oldStatus, newStatus)); + } + + public void addMachineContextStatusListener(MachineContextStatusListener ob) + { + stateListeners.add(ob); + } + + public void removeMachineContextStatusListener(MachineContextStatusListener ob) + { + stateListeners.remove(ob); } @FunctionalInterface @@ -147,4 +281,10 @@ public class MachineContext { void setMachine(Optional machine); } + + @FunctionalInterface + public static interface MachineContextStatusListener + { + void updateStatus(MachineContextStatus oldStatus, MachineContextStatus newStatus); + } } \ No newline at end of file