Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 3574 was 3217, checked in by gkronber, 15 years ago

Defined PluginDescription data contract as IsReference and changed caching scheme of plugin descriptions in the plugin store to use the plugin id as key. #951 (Refreshing the list of plugins and products of the deployment service is very slow)

File size: 10.4 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
114    #endregion
115
116    #region insert/update product
117    private void InsertOrUpdateProduct(PluginStoreClassesDataContext ctx, ProductDescription product) {
118      var productEntity = (from p in ctx.Products
119                           where p.Name == product.Name
120                           where p.Version == product.Version.ToString()
121                           select p).FirstOrDefault() ?? MakeProductFromDescription(product);
122
123      if (productEntity.Id <= 0) {
124        ctx.Products.InsertOnSubmit(productEntity);
125        ctx.SubmitChanges();
126      }
127
128      DeleteOldPlugins(ctx, productEntity);
129
130      foreach (var plugin in product.Plugins) {
131        var existingPlugin = GetExistingPlugin(ctx, plugin.Name, plugin.Version);
132        ProductPlugin prodPlugin = new ProductPlugin();
133        prodPlugin.PluginId = existingPlugin.Id;
134        prodPlugin.ProductId = productEntity.Id;
135        ctx.ProductPlugins.InsertOnSubmit(prodPlugin);
136      }
137    }
138
139    private void DeleteOldPlugins(PluginStoreClassesDataContext ctx, Product productEntity) {
140      var oldPlugins = (from p in ctx.ProductPlugins
141                        where p.ProductId == productEntity.Id
142                        select p).ToList();
143      ctx.ProductPlugins.DeleteAllOnSubmit(oldPlugins);
144      ctx.SubmitChanges();
145    }
146    #endregion
147
148    #region insert/update plugins
149    private Plugin InsertOrUpdatePlugin(PluginStoreClassesDataContext ctx, PluginDescription pluginDescription) {
150      var pluginEntity = (from p in ctx.Plugins
151                          where p.Name == pluginDescription.Name
152                          where p.Version == pluginDescription.Version.ToString()
153                          select p).FirstOrDefault() ?? MakePluginFromDescription(pluginDescription);
154
155      if (pluginEntity.Id <= 0) {
156        ctx.Plugins.InsertOnSubmit(pluginEntity);
157        ctx.SubmitChanges();
158      }
159
160      UpdatePlugin(ctx, pluginEntity, pluginDescription);
161      return pluginEntity;
162    }
163
164    private void UpdatePlugin(PluginStoreClassesDataContext ctx, Plugin pluginEntity, PluginDescription pluginDescription) {
165      // update plugin data
166      pluginEntity.License = pluginDescription.LicenseText;
167      pluginEntity.ContactName = pluginDescription.ContactName;
168      pluginEntity.ContactEmail = pluginDescription.ContactEmail;
169
170      // delete cached entry
171      if (pluginDescriptions.ContainsKey(pluginEntity.Id)) pluginDescriptions.Remove(pluginEntity.Id);
172
173      DeleteOldDependencies(ctx, pluginEntity);
174
175      foreach (var dependency in pluginDescription.Dependencies) {
176        var dependencyEntity = GetExistingPlugin(ctx, dependency.Name, dependency.Version);
177        Dependency d = new Dependency();
178        d.PluginId = pluginEntity.Id;
179        d.DependencyId = dependencyEntity.Id;
180        ctx.Dependencies.InsertOnSubmit(d);
181      }
182    }
183
184
185
186    private void DeleteOldDependencies(PluginStoreClassesDataContext ctx, Plugin pluginEntity) {
187      var oldDependencies = (from dep in ctx.Dependencies
188                             where dep.PluginId == pluginEntity.Id
189                             select dep).ToList();
190
191      ctx.Dependencies.DeleteAllOnSubmit(oldDependencies);
192      ctx.SubmitChanges();
193    }
194    #endregion
195
196    #region product <-> productDescription transformation
197    private ProductDescription MakeProductDescription(PluginStoreClassesDataContext ctx, Product p, IEnumerable<Plugin> plugins) {
198      var desc = new ProductDescription(p.Name, new Version(p.Version), from plugin in plugins
199                                                                        select MakePluginDescription(ctx, plugin));
200      return desc;
201    }
202    private Product MakeProductFromDescription(ProductDescription desc) {
203      var product = new Product();
204      product.Name = desc.Name;
205      product.Version = desc.Version.ToString();
206      return product;
207    }
208    #endregion
209
210    #region plugin <-> pluginDescription transformation
211    // cache for plugin descriptions
212    private Dictionary<long, PluginDescription> pluginDescriptions = new Dictionary<long, PluginDescription>();
213    private PluginDescription MakePluginDescription(PluginStoreClassesDataContext ctx, Plugin plugin) {
214      if (!pluginDescriptions.ContainsKey(plugin.Id)) {
215        // no cached description -> create new
216        var desc = new PluginDescription(plugin.Name, new Version(plugin.Version));
217        pluginDescriptions[plugin.Id] = desc; // and add to cache
218
219        // fill remaining properties of plugin description
220        desc.Dependencies = new List<PluginDescription>(from dep in GetDependencies(ctx, plugin) select MakePluginDescription(ctx, dep));
221        desc.ContactEmail = plugin.ContactEmail ?? string.Empty;
222        desc.ContactName = plugin.ContactName ?? string.Empty;
223        desc.LicenseText = plugin.License ?? string.Empty;
224      }
225      return pluginDescriptions[plugin.Id];
226    }
227
228    private Plugin MakePluginFromDescription(PluginDescription pluginDescription) {
229      var plugin = new Plugin();
230      plugin.Name = pluginDescription.Name;
231      plugin.Version = pluginDescription.Version.ToString();
232      plugin.ContactName = pluginDescription.ContactName;
233      plugin.ContactEmail = pluginDescription.ContactEmail;
234      plugin.License = pluginDescription.LicenseText;
235      return plugin;
236    }
237
238    private PluginPackage MakePluginPackage(Plugin plugin, byte[] pluginPackage) {
239      var package = new PluginPackage();
240      package.Data = pluginPackage;
241      package.PluginId = plugin.Id;
242      return package;
243    }
244
245    #endregion
246
247    #region helper queries
248    private Plugin GetExistingPlugin(PluginStoreClassesDataContext ctx, string name, Version version) {
249      return (from p in ctx.Plugins
250              where p.Name == name
251              where p.Version == version.ToString()
252              select p).Single();
253    }
254
255    private IEnumerable<Plugin> GetDependencies(PluginStoreClassesDataContext ctx, Plugin plugin) {
256      return from pair in ctx.Dependencies
257             from dependency in ctx.Plugins
258             where pair.PluginId == plugin.Id
259             where pair.DependencyId == dependency.Id
260             select dependency;
261    }
262    #endregion
263  }
264}
Note: See TracBrowser for help on using the repository browser.