#region License Information
/* HeuristicLab
* Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Transactions;
using System.Data.SqlClient;
using HeuristicLab.Services.Deployment.DataAccess;
namespace HeuristicLab.Services.Deployment {
public class PluginStore {
public PluginStore() {
}
#region context creating members
public IEnumerable Products {
get {
using (var ctx = new PluginStoreClassesDataContext()) {
return (from p in ctx.Products
let plugins = from pair in ctx.ProductPlugins
from plugin in ctx.Plugins
where pair.ProductId == p.Id
where plugin.Id == pair.PluginId
select plugin
select MakeProductDescription(ctx, p, plugins)).ToList();
}
}
}
public IEnumerable Plugins {
get {
using (var ctx = new PluginStoreClassesDataContext()) {
return (from plugin in ctx.Plugins
select MakePluginDescription(ctx, plugin)).ToList();
}
}
}
public byte[] PluginFile(PluginDescription pluginDescription) {
using (var ctx = new PluginStoreClassesDataContext()) {
return GetExistingPlugin(ctx, pluginDescription.Name, pluginDescription.Version).PluginPackage.Data.ToArray();
}
}
public void Persist(PluginDescription pluginDescription, byte[] pluginPackage) {
using (var ctx = new PluginStoreClassesDataContext()) {
try {
using (var transaction = new TransactionScope()) {
Plugin pluginEntity = InsertOrUpdatePlugin(ctx, pluginDescription);
if (pluginEntity.PluginPackage == null) {
// insert
pluginEntity.PluginPackage = MakePluginPackage(pluginEntity, pluginPackage);
} else {
// update
pluginEntity.PluginPackage.Data = pluginPackage;
}
ctx.SubmitChanges();
transaction.Complete();
}
}
catch (SqlException ex) {
throw new ArgumentException("Something went wrong while trying to persist plugin", ex);
}
catch (InvalidOperationException ex) {
throw new ArgumentException("Something went wrong while trying to persist plugin", ex);
}
}
}
public void Persist(ProductDescription productDescription) {
using (var ctx = new PluginStoreClassesDataContext()) {
try {
using (var transaction = new TransactionScope()) {
foreach (var plugin in productDescription.Plugins) {
var pluginEntity = GetExistingPlugin(ctx, plugin.Name, plugin.Version);
UpdatePlugin(ctx, pluginEntity, plugin);
}
InsertOrUpdateProduct(ctx, productDescription);
ctx.SubmitChanges();
transaction.Complete();
}
}
catch (SqlException ex) {
throw new ArgumentException("Something went wrong while trying to persist product", ex);
}
catch (InvalidOperationException ex) {
throw new ArgumentException("Something went wrong while trying to persist product", ex);
}
}
}
#endregion
#region insert/update product
private void InsertOrUpdateProduct(PluginStoreClassesDataContext ctx, ProductDescription product) {
var productEntity = (from p in ctx.Products
where p.Name == product.Name
where p.Version == product.Version.ToString()
select p).FirstOrDefault() ?? MakeProductFromDescription(product);
if (productEntity.Id <= 0) {
ctx.Products.InsertOnSubmit(productEntity);
ctx.SubmitChanges();
}
DeleteOldPlugins(ctx, productEntity);
foreach (var plugin in product.Plugins) {
var existingPlugin = GetExistingPlugin(ctx, plugin.Name, plugin.Version);
ProductPlugin prodPlugin = new ProductPlugin();
prodPlugin.PluginId = existingPlugin.Id;
prodPlugin.ProductId = productEntity.Id;
ctx.ProductPlugins.InsertOnSubmit(prodPlugin);
}
}
private void DeleteOldPlugins(PluginStoreClassesDataContext ctx, Product productEntity) {
var oldPlugins = (from p in ctx.ProductPlugins
where p.ProductId == productEntity.Id
select p).ToList();
ctx.ProductPlugins.DeleteAllOnSubmit(oldPlugins);
ctx.SubmitChanges();
}
#endregion
#region insert/update plugins
private Plugin InsertOrUpdatePlugin(PluginStoreClassesDataContext ctx, PluginDescription pluginDescription) {
var pluginEntity = (from p in ctx.Plugins
where p.Name == pluginDescription.Name
where p.Version == pluginDescription.Version.ToString()
select p).FirstOrDefault() ?? MakePluginFromDescription(pluginDescription);
if (pluginEntity.Id <= 0) {
ctx.Plugins.InsertOnSubmit(pluginEntity);
ctx.SubmitChanges();
}
UpdatePlugin(ctx, pluginEntity, pluginDescription);
return pluginEntity;
}
private void UpdatePlugin(PluginStoreClassesDataContext ctx, Plugin pluginEntity, PluginDescription pluginDescription) {
// update plugin data
pluginEntity.License = pluginDescription.LicenseText;
pluginEntity.ContactName = pluginDescription.ContactName;
pluginEntity.ContactEmail = pluginDescription.ContactEmail;
// delete cached entry
if (pluginDescriptions.ContainsKey(pluginEntity)) pluginDescriptions.Remove(pluginEntity);
DeleteOldDependencies(ctx, pluginEntity);
foreach (var dependency in pluginDescription.Dependencies) {
var dependencyEntity = GetExistingPlugin(ctx, dependency.Name, dependency.Version);
Dependency d = new Dependency();
d.PluginId = pluginEntity.Id;
d.DependencyId = dependencyEntity.Id;
ctx.Dependencies.InsertOnSubmit(d);
}
}
private void DeleteOldDependencies(PluginStoreClassesDataContext ctx, Plugin pluginEntity) {
var oldDependencies = (from dep in ctx.Dependencies
where dep.PluginId == pluginEntity.Id
select dep).ToList();
ctx.Dependencies.DeleteAllOnSubmit(oldDependencies);
ctx.SubmitChanges();
}
#endregion
#region product <-> productDescription transformation
private ProductDescription MakeProductDescription(PluginStoreClassesDataContext ctx, Product p, IQueryable plugins) {
var desc = new ProductDescription(p.Name, new Version(p.Version), from plugin in plugins
select MakePluginDescription(ctx, plugin));
return desc;
}
private Product MakeProductFromDescription(ProductDescription desc) {
var product = new Product();
product.Name = desc.Name;
product.Version = desc.Version.ToString();
return product;
}
#endregion
#region plugin <-> pluginDescription transformation
// cache for plugin descriptions
private Dictionary pluginDescriptions = new Dictionary();
private PluginDescription MakePluginDescription(PluginStoreClassesDataContext ctx, Plugin plugin) {
if (!pluginDescriptions.ContainsKey(plugin)) {
// no cached description -> create new
var desc = new PluginDescription(plugin.Name,
new Version(plugin.Version),
from dep in GetDependencies(ctx, plugin)
select MakePluginDescription(ctx, dep),
plugin.ContactName ?? string.Empty,
plugin.ContactEmail ?? string.Empty,
plugin.License ?? string.Empty
);
pluginDescriptions[plugin] = desc;
}
return pluginDescriptions[plugin];
}
private Plugin MakePluginFromDescription(PluginDescription pluginDescription) {
var plugin = new Plugin();
plugin.Name = pluginDescription.Name;
plugin.Version = pluginDescription.Version.ToString();
plugin.ContactName = pluginDescription.ContactName;
plugin.ContactEmail = pluginDescription.ContactEmail;
plugin.License = pluginDescription.LicenseText;
return plugin;
}
private PluginPackage MakePluginPackage(Plugin plugin, byte[] pluginPackage) {
var package = new PluginPackage();
package.Data = pluginPackage;
package.PluginId = plugin.Id;
return package;
}
#endregion
#region helper queries
private Plugin GetExistingPlugin(PluginStoreClassesDataContext ctx, string name, Version version) {
return (from p in ctx.Plugins
where p.Name == name
where p.Version == version.ToString()
select p).Single();
}
private IEnumerable GetDependencies(PluginStoreClassesDataContext ctx, Plugin plugin) {
return from pair in ctx.Dependencies
from dependency in ctx.Plugins
where pair.PluginId == plugin.Id
where pair.DependencyId == dependency.Id
select dependency;
}
#endregion
}
}