1 package net.mograsim.plugin.nature;
3 import static net.mograsim.plugin.nature.MachineContextStatus.ACTIVE;
4 import static net.mograsim.plugin.nature.MachineContextStatus.ACTIVE_CHANGED;
5 import static net.mograsim.plugin.nature.MachineContextStatus.BROKEN;
6 import static net.mograsim.plugin.nature.MachineContextStatus.CLOSED;
7 import static net.mograsim.plugin.nature.MachineContextStatus.DEAD;
8 import static net.mograsim.plugin.nature.MachineContextStatus.INTACT;
9 import static net.mograsim.plugin.nature.MachineContextStatus.READY;
10 import static net.mograsim.plugin.nature.MachineContextStatus.UNKOWN;
12 import java.io.IOException;
13 import java.util.HashSet;
14 import java.util.Objects;
15 import java.util.Optional;
18 import org.eclipse.core.resources.IProject;
19 import org.eclipse.core.runtime.CoreException;
20 import org.eclipse.jface.util.PropertyChangeEvent;
21 import org.eclipse.ui.preferences.ScopedPreferenceStore;
23 import net.mograsim.machine.Machine;
24 import net.mograsim.machine.MachineDefinition;
25 import net.mograsim.machine.MachineRegistry;
26 import net.mograsim.plugin.nature.ProjectContextEvent.ProjectContextEventType;
29 * A MachineContext is a project specific context for the Mograsim machine associated to them.
31 * It stores the {@link MachineDefinition#getId() machine id}, the {@link MachineDefinition} if applicable and an active machine if present.
32 * {@link ActiveMachineListener}s and {@link MachineContextStatusListener}s can be used to track the state of the MachineContext.
34 * @author Christian Femers
37 public class MachineContext
40 final ScopedPreferenceStore prefs;
41 Optional<String> machineId = Optional.empty();
42 Optional<MachineDefinition> machineDefinition = Optional.empty();
43 @Deprecated(forRemoval = true)
44 Optional<Machine> activeMachine = Optional.empty();
46 private MachineContextStatus status = UNKOWN;
48 @Deprecated(forRemoval = true)
49 private final Set<ActiveMachineListener> machineListeners = new HashSet<>();
50 private final Set<MachineContextStatusListener> stateListeners = new HashSet<>();
52 public MachineContext(IProject owner)
54 this.owner = Objects.requireNonNull(owner);
55 prefs = ProjectMachineContext.getProjectPrefs(owner);
56 prefs.addPropertyChangeListener(this::preferenceListener);
57 updateDefinition(ProjectMachineContext.getMachineIdFrom(prefs));
60 public final IProject getProject()
65 public final ScopedPreferenceStore getPreferences()
71 * Returns true if the project configuration is valid in the current environment
73 public final boolean isCurrentyValid()
75 return status == READY || isActive();
79 * Returns true if the persisted project configuration itself is intact
81 * @see MachineContextStatus#INTACT
83 public final boolean isIntact()
85 return isCurrentyValid() || status == INTACT;
89 * Returns true if a machine is instantiated and (possibly) running
91 @Deprecated(forRemoval = true)
92 public final boolean isActive()
94 return status == ACTIVE || status == ACTIVE_CHANGED;
98 * Returns the current status of this machine context
100 public final MachineContextStatus getStatus()
106 * Sets the projects machineId. Will likely break things, if the {@link MachineContext} {@link #isActive()}.
108 public final boolean setMachineId(String machineId)
110 prefs.setValue(ProjectMachineContext.MACHINE_PROPERTY, machineId);
115 catch (IOException e)
124 * Sets the active machine in the {@link MachineContext}'s project scope.
126 @Deprecated(forRemoval = true)
127 public final void setActiveMachine(Machine machine)
129 Optional<Machine> oldMachine = activeMachine;
130 activeMachine = Optional.ofNullable(machine);
132 notifyActiveMachineListeners(oldMachine, activeMachine);
135 public final Optional<String> getMachineId()
140 public final Optional<MachineDefinition> getMachineDefinition()
142 return machineDefinition;
145 @Deprecated(forRemoval = true)
146 public final Optional<Machine> getActiveMachine()
148 // activateMachine(); // TODO is this the best way to deal with this?
149 return activeMachine;
153 * Tries to activate the associated machine. This will not succeed if the project is not {@link MachineContextStatus#READY}. If the
154 * status is {@link MachineContextStatus#ACTIVE}, this method has no effect.
156 * @return true if the activation was successful
158 @Deprecated(forRemoval = true)
159 public final boolean activateMachine()
161 if (status == ACTIVE)
163 machineDefinition.ifPresent(md -> setActiveMachine(md.createNew()));
169 * This changes the internal status to a newly evaluated one and calls the {@link MachineContextStatusListener}s if this caused the
172 * @see #reevaluateStatus()
175 public final void updateStatus()
177 MachineContextStatus newStatus = reevaluateStatus();
178 forceUpdateStatus(newStatus);
181 final void forceUpdateStatus(MachineContextStatus newStatus)
183 MachineContextStatus oldStatus = status;
184 if (oldStatus == newStatus)
187 doPostStatusChangedAction();
188 notifyMachineContextStatusListeners(oldStatus);
192 * This method reevaluates the status <b>but does not change/update it</b>.<br>
193 * To update the status of the {@link MachineContext}, use {@link #updateStatus()}.
195 * @return the raw status of the project at the time of the call.
197 @SuppressWarnings("removal")
198 public final MachineContextStatus reevaluateStatus()
204 if (hasInvaildMograsimProject())
206 if (machineDefinition.isEmpty())
208 if (activeMachine.isEmpty())
210 if (!activeMachine.get().getDefinition().getId().equals(machineDefinition.get().getId()))
211 return ACTIVE_CHANGED;
215 @Deprecated(forRemoval = true)
216 private void doPostStatusChangedAction()
218 if ((status == DEAD || status == CLOSED) && activeMachine.isPresent())
220 Optional<Machine> oldMachine = activeMachine;
221 activeMachine = Optional.empty();
222 notifyActiveMachineListeners(oldMachine, activeMachine);
226 private boolean hasInvaildMograsimProject()
230 if (!owner.isNatureEnabled(MograsimNature.NATURE_ID))
232 return machineId.isEmpty();
234 catch (CoreException e)
236 // cannot happen, because this method is called after the exceptional states were checked.
242 final void updateDefinition(Optional<String> newMachineDefinitionId)
244 if (newMachineDefinitionId.equals(machineId))
246 machineId = newMachineDefinitionId;
247 machineDefinition = machineId.map(MachineRegistry::getMachine);
249 ProjectMachineContext.notifyListeners(new ProjectContextEvent(this, ProjectContextEventType.MACHINE_DEFINITION_CHANGE));
252 private void preferenceListener(PropertyChangeEvent changeEvent)
254 if (changeEvent.getProperty().equals(ProjectMachineContext.MACHINE_PROPERTY))
256 updateDefinition(Optional.ofNullable((String) changeEvent.getNewValue()));
260 @Deprecated(forRemoval = true)
261 private void notifyActiveMachineListeners(Optional<Machine> oldMachine, Optional<Machine> newMachine)
263 machineListeners.forEach(ob -> ob.setMachine(oldMachine, newMachine));
266 @Deprecated(forRemoval = true)
267 public void addActiveMachineListener(ActiveMachineListener ob)
269 machineListeners.add(ob);
270 ob.setMachine(Optional.empty(), activeMachine);
273 @Deprecated(forRemoval = true)
274 public void removeActiveMachineListener(ActiveMachineListener ob)
276 machineListeners.remove(ob);
279 private void notifyMachineContextStatusListeners(MachineContextStatus oldStatus)
281 MachineContextStatus newStatus = status;
282 stateListeners.forEach(ob -> ob.updateStatus(oldStatus, newStatus));
285 public void addMachineContextStatusListener(MachineContextStatusListener ob)
287 stateListeners.add(ob);
290 public void removeMachineContextStatusListener(MachineContextStatusListener ob)
292 stateListeners.remove(ob);
296 @Deprecated(forRemoval = true)
297 public static interface ActiveMachineListener
299 void setMachine(Optional<Machine> oldMachine, Optional<Machine> newMachine);
303 public static interface MachineContextStatusListener
305 void updateStatus(MachineContextStatus oldStatus, MachineContextStatus newStatus);