Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3612 was 3612, checked in by gkronber, 12 years ago

Implemented change requests of reviewers. #989 (Implement review comments in plugin infrastructure)

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