#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.Data.Linq; using System.Linq; using System.ServiceModel; using System.Web.Security; using HeuristicLab.Services.OKB.DataAccess; namespace HeuristicLab.Services.OKB { /// /// Implementation of the . /// [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class RunnerService : IRunnerService, IDisposable { /// /// Obtain a "starter kit" of information, containing: /// /// algorithm classes including algorithms /// problem classes including problems /// projects /// /// public StarterKit GetStarterKit(string platformName) { Platform platform; using (OKBDataContext okb = new OKBDataContext()) { try { platform = okb.Platforms.Single(p => p.Name == platformName); } catch (InvalidOperationException) { throw new FaultException(String.Format( "Invalid platform name \"{0}\" available platforms are: \"{1}\"", platformName, string.Join("\", \"", okb.Platforms.Select(p => p.Name).ToArray()))); } } using (OKBDataContext okb = new OKBDataContext()) { DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith(ac => ac.Algorithms); dlo.AssociateWith(ac => ac.Algorithms.Where(a => a.Platform == platform)); dlo.LoadWith(p => p.Problems); dlo.AssociateWith(pc => pc.Problems.Where(p => p.Platform == platform)); okb.LoadOptions = dlo; var StarterKit = new StarterKit() { AlgorithmClasses = okb.AlgorithmClasses.ToList(), ProblemClasses = okb.ProblemClasses.ToList() }; return StarterKit; } } /// /// Augument the given algorithm and problem entities with information /// to conduct an experiment. This will add algorithm parameters and results and /// problem characteristic values and solution representation as well as data /// necessary for deserialization. /// public ExperimentKit PrepareExperiment(Algorithm algorithm, Problem problem) { OKBDataContext okb = new OKBDataContext(); try { DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith(p => p.SolutionRepresentation); dlo.LoadWith(p => p.DataType); dlo.LoadWith(p => p.DataType); dlo.LoadWith(r => r.DataType); okb.LoadOptions = dlo; algorithm = okb.Algorithms.Single(a => a.Id == algorithm.Id); problem = okb.Problems.Single(p => p.Id == problem.Id); algorithm.AlgorithmParameters.Load(); algorithm.Results.Load(); problem.ProblemCharacteristicIntValues.Load(); problem.ProblemCharacteristicFloatValues.Load(); problem.ProblemCharacteristicStringValues.Load(); problem.ProblemParameters.Load(); return new ExperimentKit() { Algorithm = algorithm, Problem = problem }; } catch (Exception x) { throw new FaultException("Excaption caught: " + x.ToString()); } } /// /// Adds the a new /// . /// The is created if necessary as well as /// all s and s. If an /// identical experiment has been conducted before the new run is /// linked to this previous experiment instead. /// /// The algorithm. /// The problem. /// The project. public void AddRun(Algorithm algorithm, Problem problem) { try { using (OKBDataContext okb = new OKBDataContext()) { Experiment experiment = GetOrCreateExperiment(algorithm, problem, currentUser, okb); Run run = new Run() { Experiment = experiment, UserId = currentUser.Id, ClientId = currentClient.Id, FinishedDate = DateTime.Now, ResultValues = algorithm.ResultValues }; okb.Runs.InsertOnSubmit(run); okb.SubmitChanges(); } } catch (Exception x) { throw new FaultException("Could not add run: " + x.ToString()); } } private Experiment GetOrCreateExperiment(Algorithm algorithm, Problem problem, User user, OKBDataContext okb) { MatchResults(algorithm.Results, okb); EnsureParametersExist(algorithm.Parameters, okb); var experimentQuery = CreateExperimentQuery(algorithm, problem, okb); if (experimentQuery.Count() > 0) { Experiment experiment = experimentQuery.First(); return experiment; } else { Experiment experiment = new Experiment() { AlgorithmId = algorithm.Id, ProblemId = problem.Id, ParameterValues = algorithm.ParameterValues }; okb.Experiments.InsertOnSubmit(experiment); return experiment; } } private void MatchResults(IQueryable results, OKBDataContext okb) { foreach (var result in results.Where(r => r.Name != null)) { result.Id = okb.Results.Single(r => r.Name == result.Name).Id; var value = result.ResultValue; if (value != null) { result.ResultValue = (IResultValue)Activator.CreateInstance(value.GetType()); result.ResultValue.Result = result; result.ResultValue.Value = value.Value; } } } private void EnsureParametersExist(IQueryable parameters, OKBDataContext okb) { foreach (var param in parameters.Where(p => p.DataType != null && p.DataType.ClrName != null)) { DataType dataType = GetOrCreateDataType(okb, param.DataType.ClrName); param.DataType = new DataType() { Id = dataType.Id }; } okb.SubmitChanges(); var namedParams = parameters.Where(p => p.Name != null); var newParams = namedParams.Except(okb.Parameters, new NameComprarer()); foreach (var p in newParams) { okb.Parameters.InsertOnSubmit(new Parameter() { Name = p.Name, DataTypeId = p.DataTypeId, }); } okb.SubmitChanges(); foreach (var np in namedParams) { np.Id = okb.Parameters.Single(p => p.Name == np.Name).Id; var value = np.ParameterValue; if (value != null) { OperatorParameterValue opVal = value as OperatorParameterValue; np.ParameterValue = (IParameterValue)Activator.CreateInstance(value.GetType()); np.ParameterValue.Parameter = np; np.ParameterValue.Value = value.Value; if (opVal != null) { OperatorParameterValue newVal = np.ParameterValue as OperatorParameterValue; DataType dataType = GetOrCreateDataType(okb, opVal.DataType.ClrName); newVal.DataType = new DataType() { Id = dataType.Id }; } } } } private DataType GetOrCreateDataType(OKBDataContext okb, string clrName) { DataType dataType = okb.DataTypes.SingleOrDefault(dt => dt.ClrName == clrName); if (dataType == null) { dataType = new DataType() { ClrName = clrName, SqlName = "BLOB", }; okb.DataTypes.InsertOnSubmit(dataType); okb.SubmitChanges(); } return dataType; } private IQueryable CreateExperimentQuery(Algorithm algorithm, Problem problem, OKBDataContext okb) { var experimentQuery = from x in okb.Experiments where x.Algorithm == algorithm where x.Problem == problem select x; foreach (IntParameterValue ipv in algorithm.IntParameterValues) { experimentQuery = experimentQuery .Where(x => x.IntParameterValues.Any(p => p.ParameterId == ipv.ParameterId && p.Value == ipv.Value)); } foreach (FloatParameterValue fpv in algorithm.FloatParameterValues) { experimentQuery = experimentQuery .Where(x => x.FloatParameterValues.Any(p => p.ParameterId == fpv.ParameterId && p.Value == fpv.Value)); } foreach (CharParameterValue cpv in algorithm.CharParameterValues) { experimentQuery = experimentQuery .Where(x => x.CharParameterValues.Any(p => p.ParameterId == cpv.ParameterId && p.Value == cpv.Value)); } foreach (OperatorParameterValue opv in algorithm.OperatorParameterValues) { experimentQuery = experimentQuery .Where(x => x.OperatorParameterValues.Any(p => p.ParameterId == opv.ParameterId && p.DataTypeId == opv.DataTypeId)); } return experimentQuery; } /// /// Determines whether this instance is connected. /// /// /// true if this instance is connected; otherwise, false. /// public bool IsConnected() { return currentUser != null; } User currentUser = null; Client currentClient = null; /// /// Logs the specified username in. In case the user or client /// does not exist yet, they are created on the server. This /// method is currently not used for authentication but merely /// for auditing. /// /// The username. /// The clientname. /// /// true if the login was successful; false otherwise. /// public bool Login(string clientname) { MembershipUser user = Membership.GetUser(); if (user == null || string.IsNullOrEmpty(clientname) || ServiceSecurityContext.Current.IsAnonymous) { return false; } using (OKBDataContext okb = new OKBDataContext()) { currentUser = okb.Users.SingleOrDefault(u => u.Id == (Guid)user.ProviderUserKey); currentClient = okb.Clients.SingleOrDefault(c => c.Name == clientname); if (currentUser == null) { currentUser = new User() { Name = user.UserName, Id = (Guid)user.ProviderUserKey }; okb.Users.InsertOnSubmit(currentUser); okb.SubmitChanges(); } if (currentClient == null) { currentClient = new Client() { Name = clientname, Id = Guid.NewGuid() }; okb.Clients.InsertOnSubmit(currentClient); okb.SubmitChanges(); } return true; } } /// /// Logout out and closes the connection. /// public void Logout() { currentUser = null; currentClient = null; } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Logout(); } } /// /// Compares two parameters by name. /// internal class NameComprarer : IEqualityComparer { /// /// Determines whether the specified objects are equal. /// /// The first object of type to compare. /// The second object of type to compare. /// /// true if the specified objects are equal; otherwise, false. /// public bool Equals(Parameter x, Parameter y) { return x.Name == y.Name; } /// /// Returns a hash code for this instance. /// /// The obj. /// /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. /// /// /// The type of is a reference type and is null. /// public int GetHashCode(Parameter obj) { return obj.Name.GetHashCode(); } } }