Documented the ProjectMachineContext
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / nature / ProjectMachineContext.java
1 package net.mograsim.plugin.nature;
2
3 import java.util.Collections;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Map;
7 import java.util.Objects;
8 import java.util.Optional;
9 import java.util.Set;
10
11 import org.eclipse.core.resources.IProject;
12 import org.eclipse.core.resources.IResourceChangeEvent;
13 import org.eclipse.core.resources.ProjectScope;
14 import org.eclipse.core.resources.ResourcesPlugin;
15 import org.eclipse.core.runtime.Adapters;
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.IAdaptable;
18 import org.eclipse.ui.preferences.ScopedPreferenceStore;
19
20 import net.mograsim.plugin.nature.ProjectContextEvent.ProjectContextEventType;
21
22 /**
23  * This class is a register for {@link MachineContext} mapped by their {@link IProject}
24  * <p>
25  * It can be used to obtain (and thereby create if necessary) {@link MachineContext}s for projects and {@link IAdaptable}s that are somewhat
26  * associated to Mograsim nature. The register is unique and static context of this class.
27  *
28  * @author Christian Femers
29  *
30  */
31 public class ProjectMachineContext
32 {
33         private static Map<IProject, MachineContext> projectMachineContexts = Collections.synchronizedMap(new HashMap<>());
34         private static final Set<ProjectContextListener> listeners = Collections.synchronizedSet(new HashSet<>());
35
36         public static final String MOGRASIM_PROJECT_PREFS_NODE = "net.mograsim";
37         public static final String MACHINE_PROPERTY = "net.mograsim.projectMachineId";
38
39         private ProjectMachineContext()
40         {
41
42         }
43
44         /**
45          * This method returns the associated machine context or created a new one if none is associated yet.
46          * 
47          * @param project the project to get the {@link MachineContext} for (or create one, if possible). It must have Mograsim nature.
48          * 
49          * @throws IllegalArgumentException if the project is not accessible or has no mograsim nature
50          * @throws NullPointerException     if the project is null
51          * 
52          */
53         public static MachineContext getMachineContextOf(IProject project)
54         {
55                 MachineContext mc = projectMachineContexts.get(project);
56                 if (mc != null)
57                         return mc;
58                 validateMograsimNatureProject(project);
59                 mc = new MachineContext(project);
60                 projectMachineContexts.put(project, mc);
61                 notifyListeners(new ProjectContextEvent(mc, ProjectContextEventType.NEW));
62                 return mc;
63         }
64
65         /**
66          * This method returns the associated machine context or created a new one if none is associated yet. The given resource must be
67          * adaptable to {@link IProject}.
68          * 
69          * @param mograsimProjectAdapable the {@link IProject}-{@link IAdaptable} to get the {@link MachineContext} for (or create one, if
70          *                                possible). Must be contained in a Mograsim nature project.
71          * 
72          * @throws IllegalArgumentException if the project is not accessible or has no mograsim nature
73          * @throws NullPointerException     if the {@link IAdaptable} is null or it cannot be adapted to {@link IProject}
74          * 
75          */
76         public static MachineContext getMachineContextOf(IAdaptable mograsimProjectAdapable)
77         {
78                 IProject project = Adapters.adapt(mograsimProjectAdapable, IProject.class, true);
79                 Objects.requireNonNull(project, "project was null / no project found for " + mograsimProjectAdapable);
80                 return getMachineContextOf(project);
81         }
82
83         /**
84          * Returns all {@link MachineContext} known, in the sense of all that got ever created during this runtime.
85          */
86         public static Map<IProject, MachineContext> getAllProjectMachineContexts()
87         {
88                 return Collections.unmodifiableMap(projectMachineContexts);
89         }
90
91         static ScopedPreferenceStore getProjectPrefs(IProject mograsimProject)
92         {
93                 return new ScopedPreferenceStore(new ProjectScope(mograsimProject), MOGRASIM_PROJECT_PREFS_NODE);
94         }
95
96         static IProject validateMograsimNatureProject(IAdaptable mograsimProjectAdapable)
97         {
98                 IProject project;
99                 if (mograsimProjectAdapable instanceof IProject)
100                 {
101                         project = (IProject) mograsimProjectAdapable;
102                         Objects.requireNonNull(project, "Project was null");
103                 } else
104                 {
105                         project = Adapters.adapt(mograsimProjectAdapable, IProject.class, true);
106                         Objects.requireNonNull(project, () -> mograsimProjectAdapable + " is not adaptable to IProject");
107                 }
108                 try
109                 {
110                         if (!project.isNatureEnabled(MograsimNature.NATURE_ID))
111                                 throw new IllegalArgumentException(mograsimProjectAdapable + "is not (in) a Mograsim project");
112                 }
113                 catch (CoreException e)
114                 {
115                         e.printStackTrace();
116                         throw new IllegalArgumentException(mograsimProjectAdapable + " project nature could not be evaluated", e);
117                 }
118                 return project;
119         }
120
121         /**
122          * Tests for Mograsim nature. This method is null safe and will not throw any exception.
123          */
124         static boolean hasMograsimNature(IProject project)
125         {
126                 if (project == null)
127                         return false;
128                 try
129                 {
130                         return project.isNatureEnabled(MograsimNature.NATURE_ID);
131                 }
132                 catch (CoreException e)
133                 {
134                         e.printStackTrace();
135                         return false;
136                 }
137         }
138
139         static Optional<String> getMachineIdFrom(ScopedPreferenceStore preferenceStore)
140         {
141                 if (preferenceStore.contains(MACHINE_PROPERTY))
142                         return Optional.of(preferenceStore.getString(MACHINE_PROPERTY));
143                 return Optional.empty();
144         }
145
146         static void notifyListeners(ProjectContextEvent projectContextEvent)
147         {
148                 listeners.forEach(l -> l.onProjectContextChange(projectContextEvent));
149         }
150
151         public static void addProjectContextListener(ProjectContextListener listener)
152         {
153                 listeners.add(listener);
154         }
155
156         public static void removeProjectContextListener(ProjectContextListener listener)
157         {
158                 listeners.remove(listener);
159         }
160
161         static
162         {
163                 ResourcesPlugin.getWorkspace().addResourceChangeListener(ProjectMachineContext::resourceChanged);
164         }
165
166         private static void resourceChanged(IResourceChangeEvent event)
167         {
168 //              System.out.println(((ResourceChangeEvent) event).toDebugString());
169                 ProjectContextEventType eventType = ProjectContextEventType.ofResourceChangeEvent(event.getType());
170                 if (eventType == null)
171                         return;
172                 if (event.getResource() == null || event.getResource().getProject() == null)
173                         return;
174                 MachineContext mc = projectMachineContexts.get(event.getResource().getProject());
175                 if (mc == null)
176                         return;
177 //              System.out.println("  " + eventType + " - " + mc.getProject());
178                 notifyListeners(new ProjectContextEvent(mc, eventType));
179         }
180 }