source: branches/2839_HiveProjectManagement/HeuristicLab.Clients.Hive/3.3/HiveAdminClient.cs

Last change on this file was 16072, checked in by jzenisek, 14 months ago

#2839: worked on HiveProjectMgmt:

  • adapted enabled state of buttons
File size: 19.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Threading;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using System.Collections.Generic;
27using System.Linq;
28
29namespace HeuristicLab.Clients.Hive {
30  [Item("Hive Administrator", "Hive Administrator")]
31  public sealed class HiveAdminClient : IContent {
32    private static HiveAdminClient instance;
33    public static HiveAdminClient Instance {
34      get {
35        if (instance == null) instance = new HiveAdminClient();
36        return instance;
37      }
38    }
39
40    #region Properties
41    private IItemList<Resource> resources;
42    public IItemList<Resource> Resources {
43      get { return resources; }
44    }
45
46    private IItemList<Downtime> downtimes;
47    public IItemList<Downtime> Downtimes {
48      get { return downtimes; }
49    }
50
51    private Guid downtimeForResourceId;
52    public Guid DowntimeForResourceId {
53      get { return downtimeForResourceId; }
54      set {
55        downtimeForResourceId = value;
56        if (downtimes != null) {
57          downtimes.Clear();
58        }
59      }
60    }
61
62    private IItemList<Project> projects;
63    public IItemList<Project> Projects {
64      get { return projects; }
65    }
66
67    private IItemList<AssignedProjectResource> projectResourceAssignments;
68    public IItemList<AssignedProjectResource> ProjectResourceAssignments {
69      get { return projectResourceAssignments; }
70    }
71
72    private Dictionary<Guid, HiveItemCollection<Job>> jobs;
73    public Dictionary<Guid, HiveItemCollection<Job>> Jobs {
74      get { return jobs; }
75      set {
76        if (value != jobs)
77          jobs = value;
78        }
79    }
80
81    private Dictionary<Guid, HashSet<Guid>> projectAncestors;
82    public Dictionary<Guid, HashSet<Guid>> ProjectAncestors {
83      get { return projectAncestors; }
84    }
85
86    private Dictionary<Guid, HashSet<Guid>> projectDescendants;
87    public Dictionary<Guid, HashSet<Guid>> ProjectDescendants {
88      get { return projectDescendants; }
89    }
90
91    private Dictionary<Guid, HashSet<Guid>> resourceAncestors;
92    public Dictionary<Guid, HashSet<Guid>> ResourceAncestors {
93      get { return resourceAncestors; }
94    }
95
96    private Dictionary<Guid, HashSet<Guid>> resourceDescendants;
97    public Dictionary<Guid, HashSet<Guid>> ResourceDescendants {
98      get { return resourceDescendants; }
99    }
100
101    private Dictionary<Guid, string> projectNames;
102    public Dictionary<Guid, string> ProjectNames {
103      get { return projectNames; }
104    }
105
106    private HashSet<Project> disabledParentProjects;
107    public HashSet<Project> DisabledParentProjects {
108      get { return disabledParentProjects; }
109    }
110
111    private Dictionary<Guid, string> resourceNames;
112    public Dictionary<Guid, string> ResourceNames {
113      get { return resourceNames; }
114    }
115
116    private HashSet<Resource> disabledParentResources;
117    public HashSet<Resource> DisabledParentResources {
118      get { return disabledParentResources; }
119    }
120    #endregion
121
122    #region Events
123    public event EventHandler Refreshing;
124    private void OnRefreshing() {
125      EventHandler handler = Refreshing;
126      if (handler != null) handler(this, EventArgs.Empty);
127    }
128    public event EventHandler Refreshed;
129    private void OnRefreshed() {
130      var handler = Refreshed;
131      if (handler != null) handler(this, EventArgs.Empty);
132    }
133    #endregion
134
135    private HiveAdminClient() { }
136
137    #region Refresh
138    public void Refresh() {
139      OnRefreshing();
140
141      try {
142        resources = new ItemList<Resource>();
143        projects = new ItemList<Project>();
144        projectResourceAssignments = new ItemList<AssignedProjectResource>();
145        jobs = new Dictionary<Guid, HiveItemCollection<Job>>();
146        projectNames = new Dictionary<Guid, string>();
147        resourceNames = new Dictionary<Guid, string>();
148
149        projectAncestors = new Dictionary<Guid, HashSet<Guid>>();
150        projectDescendants = new Dictionary<Guid, HashSet<Guid>>();
151        resourceAncestors = new Dictionary<Guid, HashSet<Guid>>();
152        resourceDescendants = new Dictionary<Guid, HashSet<Guid>>();
153
154        HiveServiceLocator.Instance.CallHiveService(service => {
155          service.GetSlaveGroupsForAdministration().ForEach(g => resources.Add(g));
156          service.GetSlavesForAdministration().ForEach(s => resources.Add(s));
157          service.GetProjectsForAdministration().ForEach(p => projects.Add(p));
158          var projectIds = projects.Select(p => p.Id).ToList();
159          if (projectIds.Any()) {
160            service.GetAssignedResourcesForProjectsAdministration(projectIds)
161              .ForEach(a => projectResourceAssignments.Add(a));
162            projectIds.ForEach(p => jobs.Add(p, new HiveItemCollection<Job>()));
163            var unsortedJobs = service.GetJobsByProjectIds(projectIds)
164              .OrderBy(x => x.DateCreated).ToList();
165
166            unsortedJobs.Where(j => j.State == JobState.DeletionPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
167            unsortedJobs.Where(j => j.State == JobState.StatisticsPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
168            unsortedJobs.Where(j => j.State == JobState.Online).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
169
170            projectNames = service.GetProjectNames();
171            resourceNames = service.GetResourceNames();
172          }
173        });
174
175        UpdateResourceGenealogy();
176        UpdateProjectGenealogy();
177        RefreshDisabledParentProjects();
178        RefreshDisabledParentResources();
179      }
180      catch {
181        throw;
182      }
183      finally {
184        OnRefreshed();
185      }
186    }
187
188    //public void UpdateResourceGenealogy(IItemList<Resource> resources) {
189    //  resourceAncestors.Clear();
190    //  resourceDescendants.Clear();
191
192    //  foreach (var r in resources) {
193    //    resourceAncestors.Add(r.Id, new HashSet<Resource>());
194    //    resourceDescendants.Add(r.Id, new HashSet<Resource>());
195    //  }
196
197    //  foreach (var r in resources) {
198    //    var parentResourceId = r.ParentResourceId;
199    //    while (parentResourceId != null) {
200    //      var parent = resources.SingleOrDefault(x => x.Id == parentResourceId);
201    //      if (parent != null) {
202    //        resourceAncestors[r.Id].Add(parent);
203    //        resourceDescendants[parent.Id].Add(r);
204    //        parentResourceId = parent.ParentResourceId;
205    //      } else {
206    //        parentResourceId = null;
207    //      }
208    //    }
209    //  }
210    //}
211
212    //public void UpdateProjectGenealogy(IItemList<Project> projects) {
213    //  projectAncestors.Clear();
214    //  projectDescendants.Clear();
215
216    //  foreach (var p in projects) {
217    //    projectAncestors.Add(p.Id, new HashSet<Project>());
218    //    projectDescendants.Add(p.Id, new HashSet<Project>());
219    //  }
220
221    //  foreach (var p in projects) {
222    //    var parentProjectId = p.ParentProjectId;
223    //    while (parentProjectId != null) {
224    //      var parent = projects.SingleOrDefault(x => x.Id == parentProjectId);
225    //      if (parent != null) {
226    //        projectAncestors[p.Id].Add(parent);
227    //        projectDescendants[parent.Id].Add(p);
228    //        parentProjectId = parent.ParentProjectId;
229    //      } else {
230    //        parentProjectId = null;
231    //      }
232    //    }
233    //  }
234    //}
235
236    private void UpdateResourceGenealogy() {
237      resourceAncestors.Clear();
238      resourceDescendants.Clear();
239
240      // fetch resource ancestor set
241      HiveServiceLocator.Instance.CallHiveService(service => {
242        var ra = service.GetResourceGenealogy();
243        ra.Keys.ToList().ForEach(k => resourceAncestors.Add(k, new HashSet<Guid>()));
244        resourceAncestors.Keys.ToList().ForEach(k => resourceAncestors[k].UnionWith(ra[k]));
245      });
246
247      // build resource descendant set
248      resourceAncestors.Keys.ToList().ForEach(k => resourceDescendants.Add(k, new HashSet<Guid>()));
249      foreach (var ra in resourceAncestors) {
250        foreach (var ancestor in ra.Value) {
251          resourceDescendants[ancestor].Add(ra.Key);
252        }
253      }
254    }
255
256    private void UpdateProjectGenealogy() {
257      projectAncestors.Clear();
258      projectDescendants.Clear();
259
260      // fetch project ancestor list
261      HiveServiceLocator.Instance.CallHiveService(service => {
262        var pa = service.GetProjectGenealogy();
263        pa.Keys.ToList().ForEach(k => projectAncestors.Add(k, new HashSet<Guid>()));
264        projectAncestors.Keys.ToList().ForEach(k => projectAncestors[k].UnionWith(pa[k]));
265      });
266
267      // build project descendant list
268      projectAncestors.Keys.ToList().ForEach(k => projectDescendants.Add(k, new HashSet<Guid>()));
269      foreach (var pa in projectAncestors) {
270        foreach (var ancestor in pa.Value) {
271          projectDescendants[ancestor].Add(pa.Key);
272        }
273      }
274    }
275
276    private void RefreshDisabledParentProjects() {
277      disabledParentProjects = new HashSet<Project>();
278
279      foreach (var pid in projects
280        .Where(x => x.ParentProjectId.HasValue)
281        .SelectMany(x => projectAncestors[x.Id]).Distinct()
282        .Where(x => !projects.Select(y => y.Id).Contains(x))) {
283        var p = new Project();
284        p.Id = pid;
285        p.ParentProjectId = projectAncestors[pid].FirstOrDefault();
286        p.Name = projectNames[pid];
287        disabledParentProjects.Add(p);
288      }
289    }
290
291    private void RefreshDisabledParentResources() {
292      disabledParentResources = new HashSet<Resource>();
293
294      foreach (var rid in resources
295        .Where(x => x.ParentResourceId.HasValue)
296        .SelectMany(x => resourceAncestors[x.Id]).Distinct()
297        .Where(x => !resources.Select(y => y.Id).Contains(x))) {
298        var r = new SlaveGroup();
299        r.Id = rid;
300        r.ParentResourceId = resourceAncestors[rid].FirstOrDefault();
301        r.Name = resourceNames[rid];
302        disabledParentResources.Add(r);
303      }
304    }
305
306    public void RefreshJobs() {
307      var projectIds = new List<Guid>();
308      jobs = new Dictionary<Guid, HiveItemCollection<Job>>();
309
310      HiveServiceLocator.Instance.CallHiveService(service => {
311        service.GetProjectsForAdministration().ForEach(p => projectIds.Add(p.Id));
312        if(projectIds.Any()) {
313          projectIds.ForEach(p => jobs.Add(p, new HiveItemCollection<Job>()));
314          var unsortedJobs = service.GetJobsByProjectIds(projectIds)
315            .OrderBy(x => x.DateCreated).ToList();
316          unsortedJobs.Where(j => j.State == JobState.DeletionPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
317          unsortedJobs.Where(j => j.State == JobState.StatisticsPending).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
318          unsortedJobs.Where(j => j.State == JobState.Online).ToList().ForEach(j => jobs[j.ProjectId].Add(j));
319        }
320      });
321    }
322
323    public void SortJobs() {
324      for(int i = 0; i < jobs.Count; i++) {
325        var projectId = jobs.Keys.ElementAt(i);
326        var unsortedJobs = jobs.Values.ElementAt(i);
327
328        var sortedJobs = new HiveItemCollection<Job>();
329        sortedJobs.AddRange(unsortedJobs.Where(j => j.State == JobState.DeletionPending));
330        sortedJobs.AddRange(unsortedJobs.Where(j => j.State == JobState.StatisticsPending));
331        sortedJobs.AddRange(unsortedJobs.Where(j => j.State == JobState.Online));
332
333        jobs[projectId] = sortedJobs;
334      }
335    }
336
337    #endregion
338
339    #region Refresh downtime calendar
340    public void RefreshCalendar() {
341      if (downtimeForResourceId != null && downtimeForResourceId != Guid.Empty) {
342        OnRefreshing();
343
344        try {
345          downtimes = new ItemList<Downtime>();
346
347          HiveServiceLocator.Instance.CallHiveService(service => {
348            service.GetDowntimesForResource(downtimeForResourceId).ForEach(d => downtimes.Add(d));
349          });
350        }
351        catch {
352          throw;
353        }
354        finally {
355          OnRefreshed();
356        }
357      }
358    }
359    #endregion
360
361    #region Store
362    public static void Store(IHiveItem item, CancellationToken cancellationToken) {
363      if (item.Id == Guid.Empty) {
364        if (item is SlaveGroup) {
365          item.Id = HiveServiceLocator.Instance.CallHiveService((s) => s.AddSlaveGroup((SlaveGroup)item));
366        }
367        if (item is Slave) {
368          item.Id = HiveServiceLocator.Instance.CallHiveService((s) => s.AddSlave((Slave)item));
369        }
370        if (item is Downtime) {
371          item.Id = HiveServiceLocator.Instance.CallHiveService((s) => s.AddDowntime((Downtime)item));
372        }
373        if (item is Project) {
374          item.Id = HiveServiceLocator.Instance.CallHiveService(s => s.AddProject((Project)item));
375        }
376      } else {
377        if (item is SlaveGroup) {
378          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateSlaveGroup((SlaveGroup)item));
379        }
380        if (item is Slave) {
381          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateSlave((Slave)item));
382        }
383        if (item is Downtime) {
384          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateDowntime((Downtime)item));
385        }
386        if (item is Project) {
387          HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateProject((Project)item));
388        }
389      }
390    }
391    #endregion
392
393    #region Delete
394    public static void Delete(IHiveItem item) {
395      if (item is SlaveGroup) {
396        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteSlaveGroup(item.Id));
397      } else if (item is Slave) {
398        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteSlave(item.Id));
399      } else if (item is Downtime) {
400        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteDowntime(item.Id));
401      } else if (item is Project) {
402        HiveServiceLocator.Instance.CallHiveService((s) => s.DeleteProject(item.Id));
403      }
404    }
405
406    public static void DeleteJobs(List<Guid> jobIds) {
407
408      HiveServiceLocator.Instance.CallHiveService((s) => s.UpdateJobStates(jobIds, JobState.StatisticsPending));
409    }
410    #endregion
411
412    public void ResetDowntime() {
413      downtimeForResourceId = Guid.Empty;
414      if (downtimes != null) {
415        downtimes.Clear();
416      }
417    }
418
419    #region Helper
420    public IEnumerable<Project> GetAvailableProjectAncestors(Guid id) {
421      if (projectAncestors.ContainsKey(id)) return projects.Where(x => projectAncestors[id].Contains(x.Id));
422      else return Enumerable.Empty<Project>();
423    }
424
425    public IEnumerable<Project> GetAvailableProjectDescendants(Guid id) {
426      if(projectDescendants.ContainsKey(id)) return projects.Where(x => projectDescendants[id].Contains(x.Id));
427      else return Enumerable.Empty<Project>();
428    }
429
430    public IEnumerable<Resource> GetAvailableResourceAncestors(Guid id) {
431      if (resourceAncestors.ContainsKey(id)) return resources.Where(x => resourceAncestors[id].Contains(x.Id));
432      else return Enumerable.Empty<Resource>();
433    }
434
435    public IEnumerable<Resource> GetAvailableResourceDescendants(Guid id) {
436      if (resourceDescendants.ContainsKey(id)) return resources.Where(x => resourceDescendants[id].Contains(x.Id));
437      else return Enumerable.Empty<Resource>();
438    }
439
440    public bool CheckAccessToAdminAreaGranted() {
441      if(projects != null) {
442        return projects.Count > 0;
443      } else {
444        bool accessGranted = false;
445        HiveServiceLocator.Instance.CallHiveService(s => {
446          accessGranted = s.CheckAccessToAdminAreaGranted();
447        });
448        return accessGranted;
449      }
450    }
451
452    public bool CheckOwnershipOfResource(Resource res, Guid userId) {
453      if (res == null || userId == Guid.Empty) return false;
454
455      if (res.OwnerUserId == userId) {
456        return true;
457      } else if(resourceAncestors.ContainsKey(res.Id)) {
458        return GetAvailableResourceAncestors(res.Id).Where(x => x.OwnerUserId == userId).Any();
459      }
460
461      return false;
462    }
463
464    public bool CheckOwnershipOfProject(Project pro, Guid userId) {
465      if (pro == null || userId == Guid.Empty) return false;
466
467      if (pro.OwnerUserId == userId) {
468        return true;
469      } else if (projectAncestors.ContainsKey(pro.Id)) {
470        return GetAvailableProjectAncestors(pro.Id).Where(x => x.OwnerUserId == userId).Any();
471      }
472
473      return false;
474    }
475
476    public bool CheckOwnershipOfParentProject(Project pro, Guid userId) {
477      if (pro == null || userId == Guid.Empty) return false;
478
479      if(projectAncestors.ContainsKey(pro.Id)) {
480        return GetAvailableProjectAncestors(pro.Id).Where(x => x.OwnerUserId == userId).Any();
481      }
482
483      return false;
484    }
485
486    public bool CheckParentChange(Project child, Project parent) {
487      bool changePossible = true;
488
489      // change is not possible...
490      // ... if the moved project is null
491      // ... or the new parent is not stored yet
492      // ... or there is not parental change
493      if (child == null 
494        || (parent != null && parent.Id == Guid.Empty)
495        || (parent != null && parent.Id == child.ParentProjectId)) {
496        changePossible = false;
497      } else if(parent != null && projectDescendants.ContainsKey(child.Id)) {
498        // ... if the new parent is among the moved project's descendants
499        changePossible = !GetAvailableProjectDescendants(child.Id).Where(x => x.Id == parent.Id).Any();
500      }
501
502      return changePossible;
503    }
504
505    public bool CheckParentChange(Resource child, Resource parent) {
506      bool changePossible = true;
507
508      // change is not possisble...
509      // ... if the child resource is null
510      // ... or the child resource equals the parent
511      // ... or the new parent is not stored yet
512      // ... or the new parent is a slave
513      // ... or there is not parental change
514      if (child == null 
515        || child == parent
516        || (parent != null && parent.Id == Guid.Empty)
517        || (parent != null && parent is Slave)
518        || (parent != null && parent.Id == child.ParentResourceId)) {
519        changePossible = false;
520      } else if (parent != null && resourceDescendants.ContainsKey(child.Id)) {
521        // ... or if the new parent is among the moved resource's descendants
522        changePossible = !GetAvailableResourceDescendants(child.Id).Where(x => x.Id == parent.Id).Any();
523      }
524
525      return changePossible;
526    }
527    #endregion
528  }
529}
Note: See TracBrowser for help on using the repository browser.