Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Services.Deployment/3.3/PluginStore.cs @ 16565

Last change on this file since 16565 was 16565, checked in by gkronber, 5 years ago

#2520: merged changes from PersistenceOverhaul branch (r16451:16564) into trunk

File size: 11.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2019 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.Collections.Generic;
24using System.Data.SqlClient;
25using System.Linq;
26using System.Transactions;
27using HeuristicLab.Services.Deployment.DataAccess;
28
29namespace HeuristicLab.Services.Deployment {
30  public class PluginStore {
31
32    public PluginStore() {
33    }
34
35    #region context creating members
36    public IEnumerable<ProductDescription> Products {
37      get {
38        using (var ctx = new DeploymentDataContext()) {
39          return (from p in ctx.Products
40                  let plugins = from pair in ctx.ProductPlugins
41                                from plugin in ctx.Plugins
42                                where pair.ProductId == p.Id
43                                where plugin.Id == pair.PluginId
44                                select plugin
45                  select MakeProductDescription(ctx, p, plugins.ToList())).ToList();
46        }
47      }
48    }
49
50    public IEnumerable<PluginDescription> Plugins {
51      get {
52        using (var ctx = new DeploymentDataContext()) {
53          return (from plugin in ctx.Plugins
54                  select MakePluginDescription(ctx, plugin)).ToList();
55        }
56      }
57    }
58
59    public byte[] PluginFile(PluginDescription pluginDescription) {
60      using (var ctx = new DeploymentDataContext()) {
61        return GetExistingPlugin(ctx, pluginDescription.Name, pluginDescription.Version).PluginPackage.Data.ToArray();
62      }
63    }
64
65    public void Persist(PluginDescription pluginDescription, byte[] pluginPackage) {
66      using (var ctx = new DeploymentDataContext()) {
67        try {
68          using (var transaction = new TransactionScope()) {
69            Plugin pluginEntity = InsertOrUpdatePlugin(ctx, pluginDescription);
70            if (pluginEntity.PluginPackage == null) {
71              // insert
72              pluginEntity.PluginPackage = MakePluginPackage(pluginEntity, pluginPackage);
73            } else {
74              // update
75              pluginEntity.PluginPackage.Data = pluginPackage;
76            }
77            ctx.SubmitChanges();
78            transaction.Complete();
79          }
80        }
81        catch (SqlException ex) {
82          throw new ArgumentException("Something went wrong while trying to persist plugin", ex);
83        }
84        catch (InvalidOperationException ex) {
85          throw new ArgumentException("Something went wrong while trying to persist plugin", ex);
86        }
87      }
88    }
89
90    public void Persist(ProductDescription productDescription) {
91      using (var ctx = new DeploymentDataContext()) {
92        try {
93          using (var transaction = new TransactionScope()) {
94            foreach (var plugin in productDescription.Plugins) {
95              var pluginEntity = GetExistingPlugin(ctx, plugin.Name, plugin.Version);
96              UpdatePlugin(ctx, pluginEntity, plugin);
97            }
98            InsertOrUpdateProduct(ctx, productDescription);
99            ctx.SubmitChanges();
100            transaction.Complete();
101          }
102        }
103        catch (SqlException ex) {
104          throw new ArgumentException("Something went wrong while trying to persist product", ex);
105        }
106        catch (InvalidOperationException ex) {
107          throw new ArgumentException("Something went wrong while trying to persist product", ex);
108        }
109      }
110    }
111    public void Delete(ProductDescription productDescription) {
112      using (var ctx = new DeploymentDataContext()) {
113        try {
114          using (var transaction = new TransactionScope()) {
115            var productEntity = GetExistingProduct(ctx, productDescription.Name, productDescription.Version);
116
117            DeleteProductPlugins(ctx, productEntity);
118            ctx.Products.DeleteOnSubmit(productEntity);
119
120            ctx.SubmitChanges();
121            transaction.Complete();
122          }
123        }
124        catch (SqlException ex) {
125          throw new ArgumentException("Something went wrong while trying to delete product", ex);
126        }
127        catch (InvalidOperationException ex) {
128          throw new ArgumentException("Something went wrong while trying to delete product", ex);
129        }
130      }
131    }
132
133    #endregion
134
135    #region insert/update/delete product
136    private void InsertOrUpdateProduct(DeploymentDataContext ctx, ProductDescription product) {
137      var productEntity = (from p in ctx.Products
138                           where p.Name == product.Name
139                           where p.Version == product.Version.ToString()
140                           select p).FirstOrDefault() ?? MakeProductFromDescription(product);
141
142      if (productEntity.Id <= 0) {
143        ctx.Products.InsertOnSubmit(productEntity);
144        ctx.SubmitChanges();
145      }
146
147      DeleteProductPlugins(ctx, productEntity);
148
149      foreach (var plugin in product.Plugins) {
150        var existingPlugin = GetExistingPlugin(ctx, plugin.Name, plugin.Version);
151        ProductPlugin prodPlugin = new ProductPlugin();
152        prodPlugin.PluginId = existingPlugin.Id;
153        prodPlugin.ProductId = productEntity.Id;
154        ctx.ProductPlugins.InsertOnSubmit(prodPlugin);
155      }
156    }
157
158    private void DeleteProductPlugins(DeploymentDataContext ctx, Product productEntity) {
159      var oldPlugins = (from p in ctx.ProductPlugins
160                        where p.ProductId == productEntity.Id
161                        select p).ToList();
162      ctx.ProductPlugins.DeleteAllOnSubmit(oldPlugins);
163      ctx.SubmitChanges();
164    }
165    #endregion
166
167    #region insert/update plugins
168    private Plugin InsertOrUpdatePlugin(DeploymentDataContext ctx, PluginDescription pluginDescription) {
169      var pluginEntity = (from p in ctx.Plugins
170                          where p.Name == pluginDescription.Name
171                          where p.Version == pluginDescription.Version.ToString()
172                          select p).FirstOrDefault() ?? MakePluginFromDescription(pluginDescription);
173
174      if (pluginEntity.Id <= 0) {
175        ctx.Plugins.InsertOnSubmit(pluginEntity);
176        ctx.SubmitChanges();
177      }
178
179      UpdatePlugin(ctx, pluginEntity, pluginDescription);
180      return pluginEntity;
181    }
182
183    private void UpdatePlugin(DeploymentDataContext ctx, Plugin pluginEntity, PluginDescription pluginDescription) {
184      // update plugin data
185      pluginEntity.License = pluginDescription.LicenseText;
186      pluginEntity.ContactName = pluginDescription.ContactName;
187      pluginEntity.ContactEmail = pluginDescription.ContactEmail;
188
189      // delete cached entry
190      if (pluginDescriptions.ContainsKey(pluginEntity.Id)) pluginDescriptions.Remove(pluginEntity.Id);
191
192      DeleteOldDependencies(ctx, pluginEntity);
193
194      foreach (var dependency in pluginDescription.Dependencies) {
195        var dependencyEntity = GetExistingPlugin(ctx, dependency.Name, dependency.Version);
196        Dependency d = new Dependency();
197        d.PluginId = pluginEntity.Id;
198        d.DependencyId = dependencyEntity.Id;
199        ctx.Dependencies.InsertOnSubmit(d);
200      }
201    }
202
203
204
205    private void DeleteOldDependencies(DeploymentDataContext ctx, Plugin pluginEntity) {
206      var oldDependencies = (from dep in ctx.Dependencies
207                             where dep.PluginId == pluginEntity.Id
208                             select dep).ToList();
209
210      ctx.Dependencies.DeleteAllOnSubmit(oldDependencies);
211      ctx.SubmitChanges();
212    }
213    #endregion
214
215    #region product <-> productDescription transformation
216    private ProductDescription MakeProductDescription(DeploymentDataContext ctx, Product p, IEnumerable<Plugin> plugins) {
217      var desc = new ProductDescription(p.Name, new Version(p.Version), from plugin in plugins
218                                                                        select MakePluginDescription(ctx, plugin));
219      return desc;
220    }
221    private Product MakeProductFromDescription(ProductDescription desc) {
222      var product = new Product();
223      product.Name = desc.Name;
224      product.Version = desc.Version.ToString();
225      return product;
226    }
227    #endregion
228
229    #region plugin <-> pluginDescription transformation
230    // cache for plugin descriptions
231    private Dictionary<long, PluginDescription> pluginDescriptions = new Dictionary<long, PluginDescription>();
232    private PluginDescription MakePluginDescription(DeploymentDataContext ctx, Plugin plugin) {
233      if (!pluginDescriptions.ContainsKey(plugin.Id)) {
234        // no cached description -> create new
235        var desc = new PluginDescription(plugin.Name, new Version(plugin.Version));
236        pluginDescriptions[plugin.Id] = desc; // and add to cache
237
238        // fill remaining properties of plugin description
239        desc.Dependencies = new List<PluginDescription>(from dep in GetDependencies(ctx, plugin) select MakePluginDescription(ctx, dep));
240        desc.ContactEmail = plugin.ContactEmail ?? string.Empty;
241        desc.ContactName = plugin.ContactName ?? string.Empty;
242        desc.LicenseText = plugin.License ?? string.Empty;
243      }
244      return pluginDescriptions[plugin.Id];
245    }
246
247    private Plugin MakePluginFromDescription(PluginDescription pluginDescription) {
248      var plugin = new Plugin();
249      plugin.Name = pluginDescription.Name;
250      plugin.Version = pluginDescription.Version.ToString();
251      plugin.ContactName = pluginDescription.ContactName;
252      plugin.ContactEmail = pluginDescription.ContactEmail;
253      plugin.License = pluginDescription.LicenseText;
254      return plugin;
255    }
256
257    private PluginPackage MakePluginPackage(Plugin plugin, byte[] pluginPackage) {
258      var package = new PluginPackage();
259      package.Data = pluginPackage;
260      package.PluginId = plugin.Id;
261      return package;
262    }
263
264    #endregion
265
266    #region helper queries
267    private Plugin GetExistingPlugin(DeploymentDataContext ctx, string name, Version version) {
268      return (from p in ctx.Plugins
269              where p.Name == name
270              where p.Version == version.ToString()
271              select p).Single();
272    }
273
274    private Product GetExistingProduct(DeploymentDataContext ctx, string name, Version version) {
275      return (from p in ctx.Products
276              where p.Name == name
277              where p.Version == version.ToString()
278              select p).Single();
279    }
280
281    private IEnumerable<Plugin> GetDependencies(DeploymentDataContext ctx, Plugin plugin) {
282      return from pair in ctx.Dependencies
283             from dependency in ctx.Plugins
284             where pair.PluginId == plugin.Id
285             where pair.DependencyId == dependency.Id
286             select dependency;
287    }
288    #endregion
289  }
290}
Note: See TracBrowser for help on using the repository browser.