#3136
[heuristiclab.git] / HeuristicLab.PluginInfrastructure / 3.3 / Advanced / UploadPluginsView.cs
blob71dac7d7ee16bc98f7fafe14e31fe960db348ebe
1 #region License Information
2 /* HeuristicLab
3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
5 * This file is part of HeuristicLab.
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.
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.
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/>.
20 #endregion
22 using System;
23 using System.Collections.Generic;
24 using System.ComponentModel;
25 using System.Drawing;
26 using System.IO;
27 using System.IO.Compression;
28 using System.Linq;
29 using System.ServiceModel;
30 using System.Windows.Forms;
31 using HeuristicLab.PluginInfrastructure.Manager;
33 namespace HeuristicLab.PluginInfrastructure.Advanced {
34 internal partial class UploadPluginsView : InstallationManagerControl {
35 private const string UploadMessage = "Uploading plugins...";
36 private const string RefreshMessage = "Downloading plugin information from deployment service...";
38 private Dictionary<IPluginDescription, IPluginDescription> localAndServerPlugins;
39 private BackgroundWorker pluginUploadWorker;
40 private BackgroundWorker refreshPluginsWorker;
42 private PluginManager pluginManager;
43 public PluginManager PluginManager {
44 get { return pluginManager; }
45 set { pluginManager = value; }
48 public UploadPluginsView() {
49 InitializeComponent();
50 pluginImageList.Images.Add(HeuristicLab.PluginInfrastructure.Resources.Plugin);
51 localAndServerPlugins = new Dictionary<IPluginDescription, IPluginDescription>();
53 #region initialize backgroundworkers
54 pluginUploadWorker = new BackgroundWorker();
55 pluginUploadWorker.DoWork += new DoWorkEventHandler(pluginUploadWorker_DoWork);
56 pluginUploadWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(pluginUploadWorker_RunWorkerCompleted);
58 refreshPluginsWorker = new BackgroundWorker();
59 refreshPluginsWorker.DoWork += new DoWorkEventHandler(refreshPluginsWorker_DoWork);
60 refreshPluginsWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(refreshPluginsWorker_RunWorkerCompleted);
61 #endregion
64 #region refresh plugins from server backgroundworker
65 void refreshPluginsWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
66 if (e.Error != null) {
67 StatusView.ShowError("Connection Error",
68 "There was an error while connecting to the server." + Environment.NewLine +
69 "Please check your connection settings and user credentials.");
70 } else {
71 UpdatePluginListView((IEnumerable<IPluginDescription>)e.Result);
73 StatusView.HideProgressIndicator();
74 StatusView.RemoveMessage(RefreshMessage);
75 StatusView.UnlockUI();
78 void refreshPluginsWorker_DoWork(object sender, DoWorkEventArgs e) {
79 // refresh available plugins
80 var client = DeploymentService.UpdateServiceClientFactory.CreateClient();
81 try {
82 e.Result = client.GetPlugins();
83 client.Close();
85 catch (TimeoutException) {
86 client.Abort();
87 throw;
89 catch (FaultException) {
90 client.Abort();
91 throw;
93 catch (CommunicationException) {
94 client.Abort();
95 throw;
98 #endregion
100 #region upload plugins to server backgroundworker
101 void pluginUploadWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
102 if (e.Error != null) {
103 StatusView.ShowError("Connection Error",
104 "There was an error while connecting to the server." + Environment.NewLine +
105 "Please check your connection settings and user credentials.");
106 } else {
107 UpdatePluginListView((IEnumerable<IPluginDescription>)e.Result);
109 StatusView.RemoveMessage(UploadMessage);
110 StatusView.HideProgressIndicator();
111 StatusView.UnlockUI();
114 void pluginUploadWorker_DoWork(object sender, DoWorkEventArgs e) {
115 // upload plugins
116 var selectedPlugins = (IEnumerable<IPluginDescription>)e.Argument;
117 DeploymentService.AdminServiceClient adminClient = DeploymentService.AdminServiceClientFactory.CreateClient();
118 Dictionary<IPluginDescription, DeploymentService.PluginDescription> cachedPluginDescriptions =
119 new Dictionary<IPluginDescription, DeploymentService.PluginDescription>();
120 try {
121 foreach (var plugin in IteratePlugins(selectedPlugins)) {
122 adminClient.DeployPlugin(MakePluginDescription(plugin, cachedPluginDescriptions), CreateZipPackage(plugin));
124 adminClient.Close();
126 catch (TimeoutException) {
127 adminClient.Abort();
128 throw;
130 catch (FaultException) {
131 adminClient.Abort();
132 throw;
134 catch (CommunicationException) {
135 adminClient.Abort();
136 throw;
138 // refresh available plugins
139 var client = DeploymentService.UpdateServiceClientFactory.CreateClient();
140 try {
141 e.Result = client.GetPlugins();
142 client.Close();
144 catch (TimeoutException) {
145 client.Abort();
146 throw;
148 catch (FaultException) {
149 client.Abort();
150 throw;
152 catch (CommunicationException) {
153 client.Abort();
154 throw;
157 #endregion
160 #region button events
161 private void uploadButton_Click(object sender, EventArgs e) {
162 var selectedPlugins = from item in listView.Items.Cast<ListViewItem>()
163 where item.Checked
164 where item.Tag is IPluginDescription
165 select item.Tag as IPluginDescription;
166 if (selectedPlugins.Count() > 0) {
167 StatusView.LockUI();
168 StatusView.ShowProgressIndicator();
169 StatusView.ShowMessage(UploadMessage);
170 pluginUploadWorker.RunWorkerAsync(selectedPlugins.ToList());
174 private void refreshButton_Click(object sender, EventArgs e) {
175 StatusView.LockUI();
176 StatusView.ShowProgressIndicator();
177 StatusView.ShowMessage(RefreshMessage);
178 refreshPluginsWorker.RunWorkerAsync();
181 #endregion
183 #region item list events
184 private bool ignoreItemCheckedEvents = false;
185 private void listView_ItemChecked(object sender, ItemCheckedEventArgs e) {
186 if (ignoreItemCheckedEvents) return;
187 List<IPluginDescription> modifiedPlugins = new List<IPluginDescription>();
188 if (e.Item.Checked) {
189 foreach (ListViewItem item in listView.SelectedItems) {
190 var plugin = (IPluginDescription)item.Tag;
191 // also check all dependencies
192 if (!modifiedPlugins.Contains(plugin))
193 modifiedPlugins.Add(plugin);
194 foreach (var dep in Util.GetAllDependencies(plugin)) {
195 if (!modifiedPlugins.Contains(dep))
196 modifiedPlugins.Add(dep);
199 listView.CheckItems(modifiedPlugins.Select(x => FindItemForPlugin(x)));
200 } else {
201 foreach (ListViewItem item in listView.SelectedItems) {
202 var plugin = (IPluginDescription)item.Tag;
203 // also uncheck all dependent plugins
204 if (!modifiedPlugins.Contains(plugin))
205 modifiedPlugins.Add(plugin);
206 foreach (var dep in Util.GetAllDependents(plugin, localAndServerPlugins.Keys)) {
207 if (!modifiedPlugins.Contains(dep))
208 modifiedPlugins.Add(dep);
211 listView.UncheckItems(modifiedPlugins.Select(x => FindItemForPlugin(x)));
213 uploadButton.Enabled = (from i in listView.Items.OfType<ListViewItem>()
214 where i.Checked
215 select i).Any();
217 #endregion
219 #region helper methods
220 private void UpdatePluginListView(IEnumerable<IPluginDescription> remotePlugins) {
221 // refresh local plugins
222 localAndServerPlugins.Clear();
223 foreach (var plugin in pluginManager.Plugins) {
224 localAndServerPlugins.Add(plugin, null);
226 foreach (var plugin in remotePlugins) {
227 var matchingLocalPlugin = (from localPlugin in localAndServerPlugins.Keys
228 where localPlugin.Name == plugin.Name
229 where localPlugin.Version == plugin.Version
230 select localPlugin).SingleOrDefault();
231 if (matchingLocalPlugin != null) {
232 localAndServerPlugins[matchingLocalPlugin] = plugin;
235 // refresh the list view with plugins
236 listView.Items.Clear();
237 ignoreItemCheckedEvents = true;
238 foreach (var pair in localAndServerPlugins) {
239 var item = MakeListViewItem(pair.Key);
240 listView.Items.Add(item);
242 Util.ResizeColumns(listView.Columns.OfType<ColumnHeader>());
243 ignoreItemCheckedEvents = false;
246 private IEnumerable<IPluginDescription> IteratePlugins(IEnumerable<IPluginDescription> plugins) {
247 HashSet<IPluginDescription> yieldedItems = new HashSet<IPluginDescription>();
248 foreach (var plugin in plugins) {
249 foreach (var dependency in IteratePlugins(plugin.Dependencies)) {
250 if (!yieldedItems.Contains(dependency)) {
251 yieldedItems.Add(dependency);
252 yield return dependency;
255 if (!yieldedItems.Contains(plugin)) {
256 yieldedItems.Add(plugin);
257 yield return plugin;
262 private static byte[] CreateZipPackage(IPluginDescription plugin) {
263 using (MemoryStream stream = new MemoryStream()) {
264 ZipArchive zipFile = new ZipArchive(stream, ZipArchiveMode.Create);
265 foreach (var file in plugin.Files) {
266 zipFile.CreateEntry(file.Name);
268 stream.Seek(0, SeekOrigin.Begin);
269 return stream.GetBuffer();
273 private ListViewItem MakeListViewItem(IPluginDescription plugin) {
274 ListViewItem item;
275 if (localAndServerPlugins[plugin] != null) {
276 item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(),
277 localAndServerPlugins[plugin].Version.ToString(), localAndServerPlugins[plugin].Description });
278 if (plugin.Version <= localAndServerPlugins[plugin].Version)
279 item.ForeColor = Color.Gray;
280 } else {
281 item = new ListViewItem(new string[] { plugin.Name, plugin.Version.ToString(),
282 string.Empty, plugin.Description });
284 item.Tag = plugin;
285 item.ImageIndex = 0;
286 item.Checked = false;
287 return item;
290 private ListViewItem FindItemForPlugin(IPluginDescription dep) {
291 return (from i in listView.Items.Cast<ListViewItem>()
292 where i.Tag == dep
293 select i).Single();
296 private DeploymentService.PluginDescription MakePluginDescription(IPluginDescription plugin, Dictionary<IPluginDescription, DeploymentService.PluginDescription> cachedPluginDescriptions) {
297 if (!cachedPluginDescriptions.ContainsKey(plugin)) {
298 var dependencies = (from dep in plugin.Dependencies
299 select MakePluginDescription(dep, cachedPluginDescriptions))
300 .ToList();
301 cachedPluginDescriptions.Add(plugin,
302 new DeploymentService.PluginDescription(plugin.Name, plugin.Version, dependencies, plugin.ContactName, plugin.ContactEmail, plugin.LicenseText));
304 return cachedPluginDescriptions[plugin];
306 #endregion